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. 初次认识 Git (v2.x)

    什么是版本控制? 版本控制,也称为源代码控制,是一种跟踪和管理软件代码变更的实践.版本控制系统是软件工具,可帮助软件团队管理源代码随时间推移而发生的变更.随着开发环境的加速,版本控制系统可以帮助软件团 ...

  2. 深入理解 Docker 核心原理:Namespace、Cgroups 和 Rootfs

    通过这篇文章你可以了解到 Docker 容器的核心实现原理,包括 Namespace.Cgroups.Rootfs 等三个核心功能. 如果你对云原生技术充满好奇,想要深入了解更多相关的文章和资讯,欢迎 ...

  3. python 获取apk 信息

    python 获取apk 信息 1.安装androguard pip install androguard 2.获取apk的相关信息 引入基础信息 from androguard.misc impor ...

  4. DVWA Cross Site Scripting (XSS) 跨站脚本攻击

    文章目录 DVWA_XSS(Stored) 存储性XSS 1.Low 2.Medium 3.High 4.Impossible XSS平台 DVWA_XSS(Stored) 存储性XSS 一句话概括: ...

  5. C++ Traits Classes

    参考博文 https://blog.csdn.net/lihao21/article/details/55043881 Traits classes 的作用主要是用来为使用者提供类型信息.在 C++ ...

  6. 监控cpu高的进程shell

    #!/bin/bash while [ 1 ]do ps aux|awk '{if($3>10){print $3" => "$0}}' sleep 0.5sdone

  7. 第四部分_Shell脚本数组和其他变量

    数组定义 ㈠ 数组分类 普通数组:只能使用整数作为数组索引(元素的下标) 关联数组:可以使用字符串作为数组索引(元素的下标) ㈡ 普通数组定义 可以切片 一次赋予一个值 #数组名[索引下标]=值 ar ...

  8. 认识一下MRS里的“中间人”Alluxio

    摘要:Alluxio在mrs的数据处理生态中处于计算和存储之间,为上层spark.presto.mapredue.hive计算框架提供了数据抽象层,计算框架可以通过统一的客户端api和全局命名空间访问 ...

  9. 从源码角度详解Java的Callable接口

    摘要:本文从源码角度深入解析Callable接口. 本文分享自华为云社区<深入解析Callable接口>,作者: 冰 河 . 本文纯干货,从源码角度深入解析Callable接口,希望大家踏 ...

  10. 带你掌握不同平台下,探索JDK源码所需的native方法

    摘要:要探索JDK的核心底层源码,那必须掌握native用法.文章中会以"获取系统的默认时区"为例,介绍说明如何查看native对应方法的源码. 本文分享自华为云社区<要探索 ...