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的实现方式。

spring-transaction源码分析(1)概述和事务传播级别的更多相关文章

  1. spring transaction源码分析--事务架构

    1. 引言  事务特性 事务是并发控制的单元,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位.通过事务将逻辑相关的一组操作绑定在一起,以便服务器 保持数据的完整性.事 ...

  2. Spring Security 源码分析 --- WebSecurity

    概述 spring security 源码分析系列文章. 源码分析 我们想一下,我们使用 ss 框架的步骤是怎么样的. @Configuration @EnableWebSecurity @Enabl ...

  3. 精尽Spring MVC源码分析 - WebApplicationContext 容器的初始化

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  4. 精尽Spring Boot源码分析 - 序言

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  5. 精尽Spring Boot源码分析 - Jar 包的启动实现

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  6. 精尽Spring Boot源码分析 - SpringApplication 启动类的启动过程

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  7. 精尽Spring Boot源码分析 - 内嵌Tomcat容器的实现

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  8. 精尽Spring Boot源码分析 - 支持外部 Tomcat 容器的实现

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  9. 精尽Spring Boot源码分析 - 剖析 @SpringBootApplication 注解

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  10. 精尽Spring Boot源码分析 - Condition 接口的扩展

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

随机推荐

  1. 一文读懂遗传算法(附python)

    几天前,我着手解决一个实际问题--大型超市销售问题.在使用了几个简单模型做了一些特征工程之后,我在排行榜上名列第 219 名. 虽然结果不错,但是我还是想做得更好.于是,我开始研究可以提高分数的优化方 ...

  2. 【UniApp】-uni-app-自定义组件

    前言 经过上个章节的介绍,大家可以了解到 uni-app-网络请求的基本使用方法 那本章节来给大家介绍一下 uni-app-自定义组件 的基本使用方法 原本打算是直接写项目的,在写项目之前还有个内容需 ...

  3. 华企盾DSC半透明无法打开加密文件常见处理方法

    1.查看客户端日志进程是否显示legal:1 2.半透明只支持双击打开 3.半透明进程不能设置HOOK白名单 4.检查调用的进程是否都加了 5.半透明程序的运行方式不可以以管理员启动,去掉" ...

  4. TiDB故障处理之让人迷惑的Region is Unavailable

    背景 最近某集群扩容了一批物理机,其中 TiKV 节点有6台机器12个实例,同时调整了 label 设置增加了一层机柜级容灾.因为前期做了比较充分的准备工作,到了变更窗口只等着执行scale-out就 ...

  5. pycharm插件离线安装

    给不能联网的电脑或者不能访问外网的云桌面安装pycharm插件,需要离线安装 首先在能访问网络的电脑上打开插件主页,如下: 下载插件安装文件

  6. 【Python】【OpenCV】定位二维码

    相较于BarCode,QRCode有明显的特征区域,也就是左上角.右上角.左下角三个"回"字区域,得益于hierarchy中,父子关系的轮廓是连续的(下标),所以这个时候我们就可以 ...

  7. Java注解,看完就会用

    一.什么是注解 定义:注解(Annotation),也叫元数据.一种代码级别的说明. 它是JDK1.5及以后版本引入的一个特性,与类.接口.枚举是在同一个层次. 它可以声明在包.类.字段.方法.局部变 ...

  8. 2023.3 Idea配置Tomcat环境

    tomcat配置 下载tomcat 先到官网(按住Ctrl再左键点击直接打开官网)下载64位的tomcat,网速慢就用魔法下 创建项目.模块 打开idea(我用的是最新的idea的专业版,ui有点变化 ...

  9. Zabbix自带模板监控MySQL服务

    Zabbix的服务端与客户端的安装这里不再赘述了,前面也有相应的文章介绍过了,感兴趣的伙伴们可以看看历史文章就可以了,今天主要介绍下如何利用zabbix自带的模板来监控MySQL服务的一些状态,同时通 ...

  10. P2343 宝石管理系统 做题记录

    随机跳的. 一眼带修第 \(\text{k}\) 大,平衡树 / 权值线段树 / set 随便搞就行. (set 可能要双 \(\log\),所以没写) 很快啊,权值线段树就 \(\text{A}\) ...