spring-transaction源码分析(1)概述和事务传播级别

yizhihongxing

spring-tx概述

spring-tx包使用注解驱动和AOP通知将事务开启、提交/回滚、以及复杂的传播机制封装了起来,开发者不再需要编写事务管理的代码,而是可以只关注自己的业务逻辑。

本文将简单介绍spring-tx使用步骤以及七种事务传播级别。

后续文章会阅读源码,深入分析spring-tx aop通知、七种事务传播级别以及事务开启/提交/回滚的实现方式。

使用步骤

  1. 导入spring-tx依赖
  2. 使用@EnableTransactionManagement注解为应用开启事务支持
  3. 向spring容器注入一个TransactionManager实现,一般使用DataSourceTransactionManager类
  4. 在需要事务的业务方法上标注@Transactional注解即可为方法开启事务通知

Transactional注解参数

  • transactionManager - 手动指定要使用的事务管理器
  • propagation - 事务传播级别
  • isolation - 事务隔离级别
  • timeout - 事务超时时长
  • rollbackFor - 发生指定的异常时回滚事务

事务传播级别

七种级别

  • REQUIRED - Support a current transaction, create a new one if none exists. 支持当前存在的事务,如果当前没有事务,则新创建一个。默认的传播级别。

  • SUPPORTS - Support a current transaction, execute non-transactionally if none exists. 支持当前存在的事务,如果当前没有事务,则在无事务状态下运行。

    For transaction managers with transaction synchronization, SUPPORTS is slightly different from 
    no transaction at all, as it defines a transaction scope that synchronization will apply for.
    As a consequence, the same resources (JDBC Connection, Hibernate Session, etc) will be shared 
    for the entire specified scope. Note that this depends on the actual synchronization configuration 
    of the transaction manager.
    
  • MANDATORY - Support a current transaction, throw an exception if none exists. 支持当前存在的事务,如果当前没有事务,则抛出异常。

  • REQUIRES_NEW - Create a new transaction, and suspend the current transaction if one exists. 创建新事务,如果当前已存在事务则挂起这个事务,再创建新事务。

  • NOT_SUPPORTED - Execute non-transactionally, suspend the current transaction if one exists. 在无事务状态下运行,如果当前已存在事务则挂起这个事务。

  • NEVER - Execute non-transactionally, throw an exception if a transaction exists. 在无事务状态下运行,如果当前已存在事务,则抛出异常。

  • NESTED - Execute within a nested transaction if a current transaction exists, behave like REQUIRED otherwise. 如果当前已存在事务,则嵌入到当前事务中运行,否则和REQUIRED效果一样。

示例方法

在测试事务传播级别的示例中,会反复使用以下6个方法,只是给Transactional添加的参数不同而已,此处记录一下这几个方法:

public void insertBlogList(List<Blog> blogList) {
  for (int i = 0; i < blogList.size(); i++) {
    this.blogMapper.insertBlog(blogList.get(i));
  }
}

public void deleteBlogByCondition(BlogSearchParameter parameter) {
  List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  for (Blog blog : blogs) {
    this.blogMapper.deleteBlog(blog.getId());
  }
  // 抛出一个RuntimeException
  throw new RuntimeException("deleteBlogByCondition抛出一个异常");
}

public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {

  // 这里从spring容器获取service对象,避免事务失效
  BlogRequiredTxService blogService =
      this.applicationContext.getBean(BlogRequiredTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);
}

public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogRequiredTxService blogService =
      this.applicationContext.getBean(BlogRequiredTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);
}

public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogRequiredTxService blogService =
      this.applicationContext.getBean(BlogRequiredTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);
}

public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogRequiredTxService blogService =
      this.applicationContext.getBean(BlogRequiredTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);
}

传播级别详细说明

REQUIRED

Support a current transaction, create a new one if none exists.

支持当前存在的事务,如果当前没有事务,则新创建一个。默认的传播级别。

@Transactional(propagation = Propagation.REQUIRED)
public void insertBlogList(List<Blog> blogList) {
  for (int i = 0; i < blogList.size(); i++) {
    this.blogMapper.insertBlog(blogList.get(i));
  }
}

@Transactional(propagation = Propagation.REQUIRED)
public void deleteBlogByCondition(BlogSearchParameter parameter) {
  List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  for (Blog blog : blogs) {
    this.blogMapper.deleteBlog(blog.getId());
  }
  // 抛出一个RuntimeException
  throw new RuntimeException("deleteBlogByCondition抛出一个异常");

  // 如果调用方法前,没有事务,则delete操作都会回滚
  // 如果调用方法前,已经存在事务,则之前的事务操作都会回滚
}

@Transactional(propagation = Propagation.REQUIRED)
public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogRequiredTxService blogService =
      this.applicationContext.getBean(BlogRequiredTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);

  // deleteBlogByCondition方法抛出异常之后,则insertAndDeleteBlogList1方法的操作会回滚
  // 如果insertAndDeleteBlogList1方法在另一个事务中,则之前的事务操作都会回滚
}

@Transactional(propagation = Propagation.REQUIRED)
public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogRequiredTxService blogService =
      this.applicationContext.getBean(BlogRequiredTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);

  // deleteBlogByCondition方法抛出异常之后,会执行catch代码块,之后继续向下执行,
  // 执行blogService.insertBlogList(blogList)方法之后,
  // 在commit的时候检测到insertAndDeleteBlogList2方法rollback-only状态,会抛出异常:
  // org.springframework.transaction.UnexpectedRollbackException: 
  // Transaction rolled back because it has been marked as rollback-only
}

public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogRequiredTxService blogService =
      this.applicationContext.getBean(BlogRequiredTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);

  // 由于insertAndDeleteBlogList3方法没有标注Transactional注解:
  // blogService.insertBlogList(blogList)方法插入的数据会提交保存下来
  // blogService.deleteBlogByCondition(parameter)方法的删除操作会回滚
}

public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogRequiredTxService blogService =
      this.applicationContext.getBean(BlogRequiredTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);

  // 由于insertAndDeleteBlogList3方法没有标注Transactional注解:
  // blogService.insertBlogList(blogList)方法插入的数据会提交保存下来
  // blogService.deleteBlogByCondition(parameter)方法的删除操作会回滚
  // 之后会继续执行blogService.insertBlogList(blogList)再插入数据
}

REQUIRES_NEW

Create a new transaction, and suspend the current transaction if one exists.

创建新事务,如果当前已存在事务则挂起这个事务,再打开一个新的数据库连接创建新事务。

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertBlogList(List<Blog> blogList) {
  for (Blog blog : blogList) {
    this.blogMapper.insertBlog(blog);
  }
  try {
    TimeUnit.SECONDS.sleep(15);
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void deleteBlogByCondition(BlogSearchParameter parameter) {
  List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  for (Blog blog : blogs) {
    this.blogMapper.deleteBlog(blog.getId());
  }
  // 抛出一个RuntimeException
  throw new RuntimeException("deleteBlogByCondition抛出一个异常");

  // 只会回滚delete操作,因为该方法是新创建的事务
}

@Transactional
public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogRequiresNewTxService blogService =
      this.applicationContext.getBean(BlogRequiresNewTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);

  // blogService.insertBlogList(blogList)成功
  // blogService.deleteBlogByCondition(parameter)会回滚
  // 同时insertAndDeleteBlogList1中的事务也会回滚

  // 如果使用show processlist查看客户端进程,
  // 可以看到insertBlogList和deleteBlogByCondition方法创建了新的数据库连接
}

@Transactional
public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogRequiresNewTxService blogService =
      this.applicationContext.getBean(BlogRequiresNewTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);

  // blogService.insertBlogList(blogList)成功
  // blogService.deleteBlogByCondition(parameter)会回滚
  // 此时insertAndDeleteBlogList1中的事务不会回滚,因为deleteBlogByCondition(parameter)的异常被"吞掉了"
  // 后续的blogService.insertBlogList(blogList)也会成功
}

public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogRequiresNewTxService blogService =
      this.applicationContext.getBean(BlogRequiresNewTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);

  // blogService.insertBlogList(blogList)成功
  // blogService.deleteBlogByCondition(parameter)会回滚
}

public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogRequiresNewTxService blogService =
      this.applicationContext.getBean(BlogRequiresNewTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);

  // blogService.insertBlogList(blogList)成功
  // blogService.deleteBlogByCondition(parameter)会回滚
  // 后续的blogService.insertBlogList(blogList)也会成功
}

MANDATORY

Support a current transaction, throw an exception if none exists.

支持当前存在的事务,如果当前没有事务,则抛出异常。

@Transactional(propagation = Propagation.MANDATORY)
public void insertBlogList(List<Blog> blogList) {
  for (Blog blog : blogList) {
    this.blogMapper.insertBlog(blog);
  }

  // 单独调用此方法时抛错:
  // org.springframework.transaction.IllegalTransactionStateException:
  // No existing transaction found for transaction marked with propagation 'mandatory'
}

@Transactional(propagation = Propagation.MANDATORY)
public void deleteBlogByCondition(BlogSearchParameter parameter) {
  List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  for (Blog blog : blogs) {
    this.blogMapper.deleteBlog(blog.getId());
  }
  // 抛出一个RuntimeException
  throw new RuntimeException("deleteBlogByCondition抛出一个异常");

  // 单独调用此方法时抛错:
  // org.springframework.transaction.IllegalTransactionStateException:
  // No existing transaction found for transaction marked with propagation 'mandatory'
}

@Transactional
public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogMandatoryTxService blogService =
      this.applicationContext.getBean(BlogMandatoryTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);

  // deleteBlogByCondition方法抛出异常之后,则insertAndDeleteBlogList1方法的操作会回滚
  // 如果insertAndDeleteBlogList1方法在另一个事务中,则之前的事务操作都会回滚
}

@Transactional
public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogMandatoryTxService blogService =
      this.applicationContext.getBean(BlogMandatoryTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);

  // deleteBlogByCondition方法抛出异常之后,会执行catch代码块,之后继续向下执行,
  // 执行blogService.insertBlogList(blogList)方法之后,
  // 在commit的时候检测到insertAndDeleteBlogList2方法rollback-only状态,会抛出异常:
  // org.springframework.transaction.UnexpectedRollbackException: 
  // Transaction rolled back because it has been marked as rollback-only
}

public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogMandatoryTxService blogService =
      this.applicationContext.getBean(BlogMandatoryTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);

  // 抛错:
  // org.springframework.transaction.IllegalTransactionStateException:
  // No existing transaction found for transaction marked with propagation 'mandatory'
}

public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogMandatoryTxService blogService =
      this.applicationContext.getBean(BlogMandatoryTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);

  // 抛错:
  // org.springframework.transaction.IllegalTransactionStateException:
  // No existing transaction found for transaction marked with propagation 'mandatory'
}

SUPPORTS

Support a current transaction, execute non-transactionally if none exists.

支持当前存在的事务,如果当前没有事务,则在无事务状态下运行。

@Transactional(propagation = Propagation.SUPPORTS)
public void insertBlogList(List<Blog> blogList) {
  for (Blog blog : blogList) {
    this.blogMapper.insertBlog(blog);
  }
}

@Transactional(propagation = Propagation.SUPPORTS)
public void deleteBlogByCondition(BlogSearchParameter parameter) {
  List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  for (Blog blog : blogs) {
    this.blogMapper.deleteBlog(blog.getId());
  }
  // 抛出一个RuntimeException
  throw new RuntimeException("deleteBlogByCondition抛出一个异常");

  // 单独调用时删除操作成功,因为没有事务
  // 如果在一个事务中执行该方法,则会回滚
}

@Transactional
public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogSupportsTxService blogService =
      this.applicationContext.getBean(BlogSupportsTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);

  // deleteBlogByCondition方法抛出异常之后,则insertAndDeleteBlogList1方法的操作会回滚
  // 如果insertAndDeleteBlogList1方法在另一个事务中,则之前的事务操作都会回滚
}

@Transactional
public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogSupportsTxService blogService =
      this.applicationContext.getBean(BlogSupportsTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);

  // deleteBlogByCondition方法抛出异常之后,会执行catch代码块,之后继续向下执行,
  // 执行blogService.insertBlogList(blogList)方法之后,
  // 在commit的时候检测到insertAndDeleteBlogList2方法rollback-only状态,会抛出异常:
  // org.springframework.transaction.UnexpectedRollbackException: 
  // Transaction rolled back because it has been marked as rollback-only
}

public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogSupportsTxService blogService =
      this.applicationContext.getBean(BlogSupportsTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);

  // 由于insertAndDeleteBlogList3方法没有开启事务
  // 插入和删除都会成功,但是deleteBlogByCondition(parameter)还是会抛出异常
}

public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogSupportsTxService blogService =
      this.applicationContext.getBean(BlogSupportsTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);

  // 由于insertAndDeleteBlogList4方法没有开启事务
  // 插入和删除都会成功
}

NOT_SUPPORTED

Execute non-transactionally, suspend the current transaction if one exists.

在无事务状态下运行,如果当前已存在事务则挂起这个事务。

@Transactional
public void insertBlogList(List<Blog> blogList) {
  for (Blog blog : blogList) {
    this.blogMapper.insertBlog(blog);
  }
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void deleteBlogByCondition(BlogSearchParameter parameter) {
  List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  for (Blog blog : blogs) {
    this.blogMapper.deleteBlog(blog.getId());
  }
  // 抛出一个RuntimeException
  throw new RuntimeException("deleteBlogByCondition抛出一个异常");

  // 删除操作始终都会成功,但还是会抛出异常
}

@Transactional
public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogNotSupportedTxService blogService =
      this.applicationContext.getBean(BlogNotSupportedTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);

  // blogService.deleteBlogByCondition(parameter)的删除操作成功
  // deleteBlogByCondition方法抛出异常之后,则insertAndDeleteBlogList1方法的操作会回滚
  // 如果insertAndDeleteBlogList1方法在另一个事务中,则之前的事务操作都会回滚
}

@Transactional
public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogNotSupportedTxService blogService =
      this.applicationContext.getBean(BlogNotSupportedTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);

  // 插入数据和删除操作都会成功
}

public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogNotSupportedTxService blogService =
      this.applicationContext.getBean(BlogNotSupportedTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);

  // 插入数据和删除操作都会成功
  // 但是会抛出异常
}

public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogNotSupportedTxService blogService =
      this.applicationContext.getBean(BlogNotSupportedTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);

  // 插入数据和删除操作都会成功
}

NEVER

Execute non-transactionally, throw an exception if a transaction exists.在无事务状态下运行,如果当前已存在事务,则抛出异常。

@Transactional
public void insertBlogList(List<Blog> blogList) {
  for (Blog blog : blogList) {
    this.blogMapper.insertBlog(blog);
  }
}

@Transactional(propagation = Propagation.NEVER)
public void deleteBlogByCondition(BlogSearchParameter parameter) {
  List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  for (Blog blog : blogs) {
    this.blogMapper.deleteBlog(blog.getId());
  }
  // 抛出一个RuntimeException
  throw new RuntimeException("deleteBlogByCondition抛出一个异常");
}

@Transactional
public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogNeverTxService blogService =
      this.applicationContext.getBean(BlogNeverTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);

  // 插入数据操作回滚
  // 因为blogService.deleteBlogByCondition(parameter)检查到存在事务会抛出异常:
  // org.springframework.transaction.IllegalTransactionStateException:
  // Existing transaction found for transaction marked with propagation 'never'
}

@Transactional
public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogNeverTxService blogService =
      this.applicationContext.getBean(BlogNeverTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);

  // 两次插入操作会成功
  // 但是删除操作失败,因为blogService.deleteBlogByCondition(parameter)检查到存在事务会抛出异常:
  // org.springframework.transaction.IllegalTransactionStateException:
  // Existing transaction found for transaction marked with propagation 'never'
}

public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogNeverTxService blogService =
      this.applicationContext.getBean(BlogNeverTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);

  // 插入和删除都成功
  // 但是会抛出异常
}

public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogNeverTxService blogService =
      this.applicationContext.getBean(BlogNeverTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);

  // 插入和删除都成功
}

NESTED

Execute within a nested transaction if a current transaction exists, behave like REQUIRED otherwise.

如果当前已存在事务,则嵌入到当前事务中运行,否则和REQUIRED效果一样。

@Transactional(propagation = Propagation.NESTED)
public void insertBlogList(List<Blog> blogList) {
  for (Blog blog : blogList) {
    this.blogMapper.insertBlog(blog);
  }
}

@Transactional(propagation = Propagation.NESTED)
public void deleteBlogByCondition(BlogSearchParameter parameter) {
  List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  for (Blog blog : blogs) {
    this.blogMapper.deleteBlog(blog.getId());
  }
  // 抛出一个RuntimeException
  throw new RuntimeException("deleteBlogByCondition抛出一个异常");
}

@Transactional
public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogNestedTxService blogService =
      this.applicationContext.getBean(BlogNestedTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);

  // 所有操作都会回滚
}

@Transactional
public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogNestedTxService blogService =
      this.applicationContext.getBean(BlogNestedTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);

  // 前后两次插入操作成功,
  // 中间的删除操作因为抛出异常,会回滚,
  // 又因为blogService.deleteBlogByCondition(parameter)的异常被try...catch了,
  // 没有抛到insertAndDeleteBlogList2中,所以insertAndDeleteBlogList2的操作可以成功提交
}

public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogNestedTxService blogService =
      this.applicationContext.getBean(BlogNestedTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  blogService.deleteBlogByCondition(parameter);

  // 插入成功,删除回滚
}

public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {

  BlogNestedTxService blogService =
      this.applicationContext.getBean(BlogNestedTxService.class);

  // 插入数据
  blogService.insertBlogList(blogList);

  // 删除数据
  try {
    blogService.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("继续插入数据");

  // 继续插入数据
  blogService.insertBlogList(blogList);

  // 插入成功,删除回滚
}

小结

本文通过示例介绍了spring-tx的七种事务传播级别,后续的文章将阅读源码,分析spring-tx的实现方式。

原文链接:https://www.cnblogs.com/xugf/p/17376508.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:spring-transaction源码分析(1)概述和事务传播级别 - Python技术站

(0)
上一篇 2023年5月6日
下一篇 2023年5月6日

相关文章

  • Servlet与JSP间的两种传值情况

    Servlet与JSP是JavaEE中常见的Web开发组件,二者通常需要交互传递数据才能实现复杂的业务逻辑。下面我将详细讲解Servlet与JSP间的两种传值情况: 1. 通过URL参数传值 通过URL参数传值是Servlet与JSP间最简单的一种传值方式,它将数据作为URL的一部分直接传递给接收方。例如,我们可以在Servlet中使用以下代码设置URL并跳…

    Java 2023年6月15日
    00
  • MyEclipse通过JDBC连接MySQL数据库基本介绍

    首先需要在MyEclipse中配置JDBC驱动程序,具体步骤如下: 在工程中右键选择 “Properties”,然后在弹出的窗口中选择 “Java Build Path” 在 “Libraries” 标签页中,点击 “Add Library”,选择 “MySQL JDBC Driver”,点击 “Next” 确认MySQL JDBC驱动程序的位置是否正确,然…

    Java 2023年5月20日
    00
  • 深入Java Final

    深入Java Final的完整攻略 什么是Java Final Java Final关键字表示某个实体不可更改,这个实体可能是变量、方法或类。 当我们将一个变量声明为final时,它表示该变量只能被赋值一次,一旦被赋值就不能再改变。相应地,当我们将一个方法声明为final时,它表示该方法不能再被子类重写。最后,当我们将一个类声明为final时,它表示该类不能…

    Java 2023年5月26日
    00
  • struts2简介_动力节点Java学院整理

    Struts2简介 简介 Apache Struts 2 是一款基于 Java EE 的Web应用程序开发框架,它是Struts的后继者。Apache Struts 2 是一款基于MVC设计模式的框架。 特点 以下是Struts2的特点: Struts 2 是一个MVC框架,通过分离应用程序的模型、视图和控制器,为应用程序提供了松散耦合。 Struts 2跨…

    Java 2023年6月2日
    00
  • 一篇文章让你弄懂Java运算符

    一篇文章让你弄懂 Java 运算符 作为一名 Java 开发者,运算符是我们经常要用到的基本语法。在这篇文章中,我将详细讲解 Java 运算符,包括算术运算符、赋值运算符、比较运算符、逻辑运算符、位运算符等。 算术运算符 Java 中包含了常见的算术运算符,如加法、减法、乘法、除法和取模(求余数)。我们可以通过一个简单的例子来理解这些运算符的使用: int …

    Java 2023年5月23日
    00
  • Kafka使用入门教程第1/2页

    下面我会详细讲解“Kafka使用入门教程第1/2页”的完整攻略。 Kafka使用入门教程第1/2页 简介 Apache Kafka是一种高吞吐量、分布式的发布订阅消息系统。它最初由LinkedIn公司开发,之后成为了Apache软件基金会的一部分。Kafka的设计目标是通过Hadoop的并行加载机制来统一线上和离线消息处理的语义。 安装和环境配置 在进行Ka…

    Java 2023年5月20日
    00
  • Java计时新姿势StopWatch的使用方法详解

    Java计时新姿势StopWatch的使用方法详解 简介 StopWatch是Spring框架中的一个计时器工具类,它提供了在Java应用程序中精确计时的方式,并且允许您分离暂停和继续计时。该工具类的代码在Spring框架中,但是它是一个独立的类库,您可以在任何Java代码中使用它。本文将介绍如何使用StopWatch计时,并解释其不同的用法。 依赖导入 在…

    Java 2023年5月20日
    00
  • Java中的HashSet是什么?

    Java中的HashSet是什么? Java中的HashSet是一种基于哈希表实现的无序集合,可以存储不重复的元素。它实现了Set接口,继承自AbstractSet类。HashSet中的元素不按照特定的方式排序,而是根据元素的哈希码来存储和检索元素。 HashSet内部实现了一个HashMap,将元素作为key,value则对应一个常量Object对象。通过…

    Java 2023年4月27日
    00
合作推广
合作推广
分享本页
返回顶部