IT评测·应用市场-qidao123.com

标题: spring-transaction源码分析(1)概述和事务传播级别 [打印本页]

作者: 张春    时间: 2023-5-6 11:04
标题: spring-transaction源码分析(1)概述和事务传播级别
spring-tx概述

spring-tx包使用注解驱动和AOP通知将事务开启、提交/回滚、以及复杂的传播机制封装了起来,开发者不再需要编写事务管理的代码,而是可以只关注自己的业务逻辑。
本文将简单介绍spring-tx使用步骤以及七种事务传播级别。
后续文章会阅读源码,深入分析spring-tx aop通知、七种事务传播级别以及事务开启/提交/回滚的实现方式。
使用步骤

Transactional注解参数

事务传播级别

七种级别

示例方法

在测试事务传播级别的示例中,会反复使用以下6个方法,只是给Transactional添加的参数不同而已,此处记录一下这几个方法:
  1. public void insertBlogList(List<Blog> blogList) {
  2.   for (int i = 0; i < blogList.size(); i++) {
  3.     this.blogMapper.insertBlog(blogList.get(i));
  4.   }
  5. }
  6. public void deleteBlogByCondition(BlogSearchParameter parameter) {
  7.   List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  8.   for (Blog blog : blogs) {
  9.     this.blogMapper.deleteBlog(blog.getId());
  10.   }
  11.   // 抛出一个RuntimeException
  12.   throw new RuntimeException("deleteBlogByCondition抛出一个异常");
  13. }
  14. public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {
  15.   // 这里从spring容器获取service对象,避免事务失效
  16.   BlogRequiredTxService blogService =
  17.       this.applicationContext.getBean(BlogRequiredTxService.class);
  18.   // 插入数据
  19.   blogService.insertBlogList(blogList);
  20.   // 删除数据
  21.   blogService.deleteBlogByCondition(parameter);
  22. }
  23. public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {
  24.   BlogRequiredTxService blogService =
  25.       this.applicationContext.getBean(BlogRequiredTxService.class);
  26.   // 插入数据
  27.   blogService.insertBlogList(blogList);
  28.   // 删除数据
  29.   try {
  30.     blogService.deleteBlogByCondition(parameter);
  31.   } catch (Exception e) {
  32.     System.err.printf("Err:%s%n", e.getMessage());
  33.   }
  34.   System.out.println("继续插入数据");
  35.   // 继续插入数据
  36.   blogService.insertBlogList(blogList);
  37. }
  38. public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {
  39.   BlogRequiredTxService blogService =
  40.       this.applicationContext.getBean(BlogRequiredTxService.class);
  41.   // 插入数据
  42.   blogService.insertBlogList(blogList);
  43.   // 删除数据
  44.   blogService.deleteBlogByCondition(parameter);
  45. }
  46. public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {
  47.   BlogRequiredTxService blogService =
  48.       this.applicationContext.getBean(BlogRequiredTxService.class);
  49.   // 插入数据
  50.   blogService.insertBlogList(blogList);
  51.   // 删除数据
  52.   try {
  53.     blogService.deleteBlogByCondition(parameter);
  54.   } catch (Exception e) {
  55.     System.err.printf("Err:%s%n", e.getMessage());
  56.   }
  57.   System.out.println("继续插入数据");
  58.   // 继续插入数据
  59.   blogService.insertBlogList(blogList);
  60. }
复制代码
传播级别详细说明

REQUIRED

Support a current transaction, create a new one if none exists.
支持当前存在的事务,如果当前没有事务,则新创建一个。默认的传播级别。
  1. @Transactional(propagation = Propagation.REQUIRED)
  2. public void insertBlogList(List<Blog> blogList) {
  3.   for (int i = 0; i < blogList.size(); i++) {
  4.     this.blogMapper.insertBlog(blogList.get(i));
  5.   }
  6. }
  7. @Transactional(propagation = Propagation.REQUIRED)
  8. public void deleteBlogByCondition(BlogSearchParameter parameter) {
  9.   List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  10.   for (Blog blog : blogs) {
  11.     this.blogMapper.deleteBlog(blog.getId());
  12.   }
  13.   // 抛出一个RuntimeException
  14.   throw new RuntimeException("deleteBlogByCondition抛出一个异常");
  15.   // 如果调用方法前,没有事务,则delete操作都会回滚
  16.   // 如果调用方法前,已经存在事务,则之前的事务操作都会回滚
  17. }
  18. @Transactional(propagation = Propagation.REQUIRED)
  19. public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {
  20.   BlogRequiredTxService blogService =
  21.       this.applicationContext.getBean(BlogRequiredTxService.class);
  22.   // 插入数据
  23.   blogService.insertBlogList(blogList);
  24.   // 删除数据
  25.   blogService.deleteBlogByCondition(parameter);
  26.   // deleteBlogByCondition方法抛出异常之后,则insertAndDeleteBlogList1方法的操作会回滚
  27.   // 如果insertAndDeleteBlogList1方法在另一个事务中,则之前的事务操作都会回滚
  28. }
  29. @Transactional(propagation = Propagation.REQUIRED)
  30. public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {
  31.   BlogRequiredTxService blogService =
  32.       this.applicationContext.getBean(BlogRequiredTxService.class);
  33.   // 插入数据
  34.   blogService.insertBlogList(blogList);
  35.   // 删除数据
  36.   try {
  37.     blogService.deleteBlogByCondition(parameter);
  38.   } catch (Exception e) {
  39.     System.err.printf("Err:%s%n", e.getMessage());
  40.   }
  41.   System.out.println("继续插入数据");
  42.   // 继续插入数据
  43.   blogService.insertBlogList(blogList);
  44.   // deleteBlogByCondition方法抛出异常之后,会执行catch代码块,之后继续向下执行,
  45.   // 执行blogService.insertBlogList(blogList)方法之后,
  46.   // 在commit的时候检测到insertAndDeleteBlogList2方法rollback-only状态,会抛出异常:
  47.   // org.springframework.transaction.UnexpectedRollbackException:
  48.   // Transaction rolled back because it has been marked as rollback-only
  49. }
  50. public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {
  51.   BlogRequiredTxService blogService =
  52.       this.applicationContext.getBean(BlogRequiredTxService.class);
  53.   // 插入数据
  54.   blogService.insertBlogList(blogList);
  55.   // 删除数据
  56.   blogService.deleteBlogByCondition(parameter);
  57.   // 由于insertAndDeleteBlogList3方法没有标注Transactional注解:
  58.   // blogService.insertBlogList(blogList)方法插入的数据会提交保存下来
  59.   // blogService.deleteBlogByCondition(parameter)方法的删除操作会回滚
  60. }
  61. public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {
  62.   BlogRequiredTxService blogService =
  63.       this.applicationContext.getBean(BlogRequiredTxService.class);
  64.   // 插入数据
  65.   blogService.insertBlogList(blogList);
  66.   // 删除数据
  67.   try {
  68.     blogService.deleteBlogByCondition(parameter);
  69.   } catch (Exception e) {
  70.     System.err.printf("Err:%s%n", e.getMessage());
  71.   }
  72.   System.out.println("继续插入数据");
  73.   // 继续插入数据
  74.   blogService.insertBlogList(blogList);
  75.   // 由于insertAndDeleteBlogList3方法没有标注Transactional注解:
  76.   // blogService.insertBlogList(blogList)方法插入的数据会提交保存下来
  77.   // blogService.deleteBlogByCondition(parameter)方法的删除操作会回滚
  78.   // 之后会继续执行blogService.insertBlogList(blogList)再插入数据
  79. }
复制代码
REQUIRES_NEW

Create a new transaction, and suspend the current transaction if one exists.
创建新事务,如果当前已存在事务则挂起这个事务,再打开一个新的数据库连接创建新事务。
  1. @Transactional(propagation = Propagation.REQUIRES_NEW)
  2. public void insertBlogList(List<Blog> blogList) {
  3.   for (Blog blog : blogList) {
  4.     this.blogMapper.insertBlog(blog);
  5.   }
  6.   try {
  7.     TimeUnit.SECONDS.sleep(15);
  8.   } catch (InterruptedException e) {
  9.     e.printStackTrace();
  10.   }
  11. }
  12. @Transactional(propagation = Propagation.REQUIRES_NEW)
  13. public void deleteBlogByCondition(BlogSearchParameter parameter) {
  14.   List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  15.   for (Blog blog : blogs) {
  16.     this.blogMapper.deleteBlog(blog.getId());
  17.   }
  18.   // 抛出一个RuntimeException
  19.   throw new RuntimeException("deleteBlogByCondition抛出一个异常");
  20.   // 只会回滚delete操作,因为该方法是新创建的事务
  21. }
  22. @Transactional
  23. public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {
  24.   BlogRequiresNewTxService blogService =
  25.       this.applicationContext.getBean(BlogRequiresNewTxService.class);
  26.   // 插入数据
  27.   blogService.insertBlogList(blogList);
  28.   // 删除数据
  29.   blogService.deleteBlogByCondition(parameter);
  30.   // blogService.insertBlogList(blogList)成功
  31.   // blogService.deleteBlogByCondition(parameter)会回滚
  32.   // 同时insertAndDeleteBlogList1中的事务也会回滚
  33.   // 如果使用show processlist查看客户端进程,
  34.   // 可以看到insertBlogList和deleteBlogByCondition方法创建了新的数据库连接
  35. }
  36. @Transactional
  37. public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {
  38.   BlogRequiresNewTxService blogService =
  39.       this.applicationContext.getBean(BlogRequiresNewTxService.class);
  40.   // 插入数据
  41.   blogService.insertBlogList(blogList);
  42.   // 删除数据
  43.   try {
  44.     blogService.deleteBlogByCondition(parameter);
  45.   } catch (Exception e) {
  46.     System.err.printf("Err:%s%n", e.getMessage());
  47.   }
  48.   System.out.println("继续插入数据");
  49.   // 继续插入数据
  50.   blogService.insertBlogList(blogList);
  51.   // blogService.insertBlogList(blogList)成功
  52.   // blogService.deleteBlogByCondition(parameter)会回滚
  53.   // 此时insertAndDeleteBlogList1中的事务不会回滚,因为deleteBlogByCondition(parameter)的异常被"吞掉了"
  54.   // 后续的blogService.insertBlogList(blogList)也会成功
  55. }
  56. public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {
  57.   BlogRequiresNewTxService blogService =
  58.       this.applicationContext.getBean(BlogRequiresNewTxService.class);
  59.   // 插入数据
  60.   blogService.insertBlogList(blogList);
  61.   // 删除数据
  62.   blogService.deleteBlogByCondition(parameter);
  63.   // blogService.insertBlogList(blogList)成功
  64.   // blogService.deleteBlogByCondition(parameter)会回滚
  65. }
  66. public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {
  67.   BlogRequiresNewTxService blogService =
  68.       this.applicationContext.getBean(BlogRequiresNewTxService.class);
  69.   // 插入数据
  70.   blogService.insertBlogList(blogList);
  71.   // 删除数据
  72.   try {
  73.     blogService.deleteBlogByCondition(parameter);
  74.   } catch (Exception e) {
  75.     System.err.printf("Err:%s%n", e.getMessage());
  76.   }
  77.   System.out.println("继续插入数据");
  78.   // 继续插入数据
  79.   blogService.insertBlogList(blogList);
  80.   // blogService.insertBlogList(blogList)成功
  81.   // blogService.deleteBlogByCondition(parameter)会回滚
  82.   // 后续的blogService.insertBlogList(blogList)也会成功
  83. }
复制代码
MANDATORY

Support a current transaction, throw an exception if none exists.
支持当前存在的事务,如果当前没有事务,则抛出异常。
  1. @Transactional(propagation = Propagation.MANDATORY)
  2. public void insertBlogList(List<Blog> blogList) {
  3.   for (Blog blog : blogList) {
  4.     this.blogMapper.insertBlog(blog);
  5.   }
  6.   // 单独调用此方法时抛错:
  7.   // org.springframework.transaction.IllegalTransactionStateException:
  8.   // No existing transaction found for transaction marked with propagation 'mandatory'
  9. }
  10. @Transactional(propagation = Propagation.MANDATORY)
  11. public void deleteBlogByCondition(BlogSearchParameter parameter) {
  12.   List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  13.   for (Blog blog : blogs) {
  14.     this.blogMapper.deleteBlog(blog.getId());
  15.   }
  16.   // 抛出一个RuntimeException
  17.   throw new RuntimeException("deleteBlogByCondition抛出一个异常");
  18.   // 单独调用此方法时抛错:
  19.   // org.springframework.transaction.IllegalTransactionStateException:
  20.   // No existing transaction found for transaction marked with propagation 'mandatory'
  21. }
  22. @Transactional
  23. public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {
  24.   BlogMandatoryTxService blogService =
  25.       this.applicationContext.getBean(BlogMandatoryTxService.class);
  26.   // 插入数据
  27.   blogService.insertBlogList(blogList);
  28.   // 删除数据
  29.   blogService.deleteBlogByCondition(parameter);
  30.   // deleteBlogByCondition方法抛出异常之后,则insertAndDeleteBlogList1方法的操作会回滚
  31.   // 如果insertAndDeleteBlogList1方法在另一个事务中,则之前的事务操作都会回滚
  32. }
  33. @Transactional
  34. public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {
  35.   BlogMandatoryTxService blogService =
  36.       this.applicationContext.getBean(BlogMandatoryTxService.class);
  37.   // 插入数据
  38.   blogService.insertBlogList(blogList);
  39.   // 删除数据
  40.   try {
  41.     blogService.deleteBlogByCondition(parameter);
  42.   } catch (Exception e) {
  43.     System.err.printf("Err:%s%n", e.getMessage());
  44.   }
  45.   System.out.println("继续插入数据");
  46.   // 继续插入数据
  47.   blogService.insertBlogList(blogList);
  48.   // deleteBlogByCondition方法抛出异常之后,会执行catch代码块,之后继续向下执行,
  49.   // 执行blogService.insertBlogList(blogList)方法之后,
  50.   // 在commit的时候检测到insertAndDeleteBlogList2方法rollback-only状态,会抛出异常:
  51.   // org.springframework.transaction.UnexpectedRollbackException:
  52.   // Transaction rolled back because it has been marked as rollback-only
  53. }
  54. public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {
  55.   BlogMandatoryTxService blogService =
  56.       this.applicationContext.getBean(BlogMandatoryTxService.class);
  57.   // 插入数据
  58.   blogService.insertBlogList(blogList);
  59.   // 删除数据
  60.   blogService.deleteBlogByCondition(parameter);
  61.   // 抛错:
  62.   // org.springframework.transaction.IllegalTransactionStateException:
  63.   // No existing transaction found for transaction marked with propagation 'mandatory'
  64. }
  65. public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {
  66.   BlogMandatoryTxService blogService =
  67.       this.applicationContext.getBean(BlogMandatoryTxService.class);
  68.   // 插入数据
  69.   blogService.insertBlogList(blogList);
  70.   // 删除数据
  71.   try {
  72.     blogService.deleteBlogByCondition(parameter);
  73.   } catch (Exception e) {
  74.     System.err.printf("Err:%s%n", e.getMessage());
  75.   }
  76.   System.out.println("继续插入数据");
  77.   // 继续插入数据
  78.   blogService.insertBlogList(blogList);
  79.   // 抛错:
  80.   // org.springframework.transaction.IllegalTransactionStateException:
  81.   // No existing transaction found for transaction marked with propagation 'mandatory'
  82. }
复制代码
SUPPORTS

Support a current transaction, execute non-transactionally if none exists.
支持当前存在的事务,如果当前没有事务,则在无事务状态下运行。
  1. @Transactional(propagation = Propagation.SUPPORTS)
  2. public void insertBlogList(List<Blog> blogList) {
  3.   for (Blog blog : blogList) {
  4.     this.blogMapper.insertBlog(blog);
  5.   }
  6. }
  7. @Transactional(propagation = Propagation.SUPPORTS)
  8. public void deleteBlogByCondition(BlogSearchParameter parameter) {
  9.   List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  10.   for (Blog blog : blogs) {
  11.     this.blogMapper.deleteBlog(blog.getId());
  12.   }
  13.   // 抛出一个RuntimeException
  14.   throw new RuntimeException("deleteBlogByCondition抛出一个异常");
  15.   // 单独调用时删除操作成功,因为没有事务
  16.   // 如果在一个事务中执行该方法,则会回滚
  17. }
  18. @Transactional
  19. public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {
  20.   BlogSupportsTxService blogService =
  21.       this.applicationContext.getBean(BlogSupportsTxService.class);
  22.   // 插入数据
  23.   blogService.insertBlogList(blogList);
  24.   // 删除数据
  25.   blogService.deleteBlogByCondition(parameter);
  26.   // deleteBlogByCondition方法抛出异常之后,则insertAndDeleteBlogList1方法的操作会回滚
  27.   // 如果insertAndDeleteBlogList1方法在另一个事务中,则之前的事务操作都会回滚
  28. }
  29. @Transactional
  30. public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {
  31.   BlogSupportsTxService blogService =
  32.       this.applicationContext.getBean(BlogSupportsTxService.class);
  33.   // 插入数据
  34.   blogService.insertBlogList(blogList);
  35.   // 删除数据
  36.   try {
  37.     blogService.deleteBlogByCondition(parameter);
  38.   } catch (Exception e) {
  39.     System.err.printf("Err:%s%n", e.getMessage());
  40.   }
  41.   System.out.println("继续插入数据");
  42.   // 继续插入数据
  43.   blogService.insertBlogList(blogList);
  44.   // deleteBlogByCondition方法抛出异常之后,会执行catch代码块,之后继续向下执行,
  45.   // 执行blogService.insertBlogList(blogList)方法之后,
  46.   // 在commit的时候检测到insertAndDeleteBlogList2方法rollback-only状态,会抛出异常:
  47.   // org.springframework.transaction.UnexpectedRollbackException:
  48.   // Transaction rolled back because it has been marked as rollback-only
  49. }
  50. public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {
  51.   BlogSupportsTxService blogService =
  52.       this.applicationContext.getBean(BlogSupportsTxService.class);
  53.   // 插入数据
  54.   blogService.insertBlogList(blogList);
  55.   // 删除数据
  56.   blogService.deleteBlogByCondition(parameter);
  57.   // 由于insertAndDeleteBlogList3方法没有开启事务
  58.   // 插入和删除都会成功,但是deleteBlogByCondition(parameter)还是会抛出异常
  59. }
  60. public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {
  61.   BlogSupportsTxService blogService =
  62.       this.applicationContext.getBean(BlogSupportsTxService.class);
  63.   // 插入数据
  64.   blogService.insertBlogList(blogList);
  65.   // 删除数据
  66.   try {
  67.     blogService.deleteBlogByCondition(parameter);
  68.   } catch (Exception e) {
  69.     System.err.printf("Err:%s%n", e.getMessage());
  70.   }
  71.   System.out.println("继续插入数据");
  72.   // 继续插入数据
  73.   blogService.insertBlogList(blogList);
  74.   // 由于insertAndDeleteBlogList4方法没有开启事务
  75.   // 插入和删除都会成功
  76. }
复制代码
NOT_SUPPORTED

Execute non-transactionally, suspend the current transaction if one exists.
在无事务状态下运行,如果当前已存在事务则挂起这个事务。
  1. @Transactional
  2. public void insertBlogList(List<Blog> blogList) {
  3.   for (Blog blog : blogList) {
  4.     this.blogMapper.insertBlog(blog);
  5.   }
  6. }
  7. @Transactional(propagation = Propagation.NOT_SUPPORTED)
  8. public void deleteBlogByCondition(BlogSearchParameter parameter) {
  9.   List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  10.   for (Blog blog : blogs) {
  11.     this.blogMapper.deleteBlog(blog.getId());
  12.   }
  13.   // 抛出一个RuntimeException
  14.   throw new RuntimeException("deleteBlogByCondition抛出一个异常");
  15.   // 删除操作始终都会成功,但还是会抛出异常
  16. }
  17. @Transactional
  18. public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {
  19.   BlogNotSupportedTxService blogService =
  20.       this.applicationContext.getBean(BlogNotSupportedTxService.class);
  21.   // 插入数据
  22.   blogService.insertBlogList(blogList);
  23.   // 删除数据
  24.   blogService.deleteBlogByCondition(parameter);
  25.   // blogService.deleteBlogByCondition(parameter)的删除操作成功
  26.   // deleteBlogByCondition方法抛出异常之后,则insertAndDeleteBlogList1方法的操作会回滚
  27.   // 如果insertAndDeleteBlogList1方法在另一个事务中,则之前的事务操作都会回滚
  28. }
  29. @Transactional
  30. public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {
  31.   BlogNotSupportedTxService blogService =
  32.       this.applicationContext.getBean(BlogNotSupportedTxService.class);
  33.   // 插入数据
  34.   blogService.insertBlogList(blogList);
  35.   // 删除数据
  36.   try {
  37.     blogService.deleteBlogByCondition(parameter);
  38.   } catch (Exception e) {
  39.     System.err.printf("Err:%s%n", e.getMessage());
  40.   }
  41.   System.out.println("继续插入数据");
  42.   // 继续插入数据
  43.   blogService.insertBlogList(blogList);
  44.   // 插入数据和删除操作都会成功
  45. }
  46. public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {
  47.   BlogNotSupportedTxService blogService =
  48.       this.applicationContext.getBean(BlogNotSupportedTxService.class);
  49.   // 插入数据
  50.   blogService.insertBlogList(blogList);
  51.   // 删除数据
  52.   blogService.deleteBlogByCondition(parameter);
  53.   // 插入数据和删除操作都会成功
  54.   // 但是会抛出异常
  55. }
  56. public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {
  57.   BlogNotSupportedTxService blogService =
  58.       this.applicationContext.getBean(BlogNotSupportedTxService.class);
  59.   // 插入数据
  60.   blogService.insertBlogList(blogList);
  61.   // 删除数据
  62.   try {
  63.     blogService.deleteBlogByCondition(parameter);
  64.   } catch (Exception e) {
  65.     System.err.printf("Err:%s%n", e.getMessage());
  66.   }
  67.   System.out.println("继续插入数据");
  68.   // 继续插入数据
  69.   blogService.insertBlogList(blogList);
  70.   // 插入数据和删除操作都会成功
  71. }
复制代码
NEVER

Execute non-transactionally, throw an exception if a transaction exists.在无事务状态下运行,如果当前已存在事务,则抛出异常。
  1. @Transactional
  2. public void insertBlogList(List<Blog> blogList) {
  3.   for (Blog blog : blogList) {
  4.     this.blogMapper.insertBlog(blog);
  5.   }
  6. }
  7. @Transactional(propagation = Propagation.NEVER)
  8. public void deleteBlogByCondition(BlogSearchParameter parameter) {
  9.   List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  10.   for (Blog blog : blogs) {
  11.     this.blogMapper.deleteBlog(blog.getId());
  12.   }
  13.   // 抛出一个RuntimeException
  14.   throw new RuntimeException("deleteBlogByCondition抛出一个异常");
  15. }
  16. @Transactional
  17. public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {
  18.   BlogNeverTxService blogService =
  19.       this.applicationContext.getBean(BlogNeverTxService.class);
  20.   // 插入数据
  21.   blogService.insertBlogList(blogList);
  22.   // 删除数据
  23.   blogService.deleteBlogByCondition(parameter);
  24.   // 插入数据操作回滚
  25.   // 因为blogService.deleteBlogByCondition(parameter)检查到存在事务会抛出异常:
  26.   // org.springframework.transaction.IllegalTransactionStateException:
  27.   // Existing transaction found for transaction marked with propagation 'never'
  28. }
  29. @Transactional
  30. public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {
  31.   BlogNeverTxService blogService =
  32.       this.applicationContext.getBean(BlogNeverTxService.class);
  33.   // 插入数据
  34.   blogService.insertBlogList(blogList);
  35.   // 删除数据
  36.   try {
  37.     blogService.deleteBlogByCondition(parameter);
  38.   } catch (Exception e) {
  39.     System.err.printf("Err:%s%n", e.getMessage());
  40.   }
  41.   System.out.println("继续插入数据");
  42.   // 继续插入数据
  43.   blogService.insertBlogList(blogList);
  44.   // 两次插入操作会成功
  45.   // 但是删除操作失败,因为blogService.deleteBlogByCondition(parameter)检查到存在事务会抛出异常:
  46.   // org.springframework.transaction.IllegalTransactionStateException:
  47.   // Existing transaction found for transaction marked with propagation 'never'
  48. }
  49. public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {
  50.   BlogNeverTxService blogService =
  51.       this.applicationContext.getBean(BlogNeverTxService.class);
  52.   // 插入数据
  53.   blogService.insertBlogList(blogList);
  54.   // 删除数据
  55.   blogService.deleteBlogByCondition(parameter);
  56.   // 插入和删除都成功
  57.   // 但是会抛出异常
  58. }
  59. public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {
  60.   BlogNeverTxService blogService =
  61.       this.applicationContext.getBean(BlogNeverTxService.class);
  62.   // 插入数据
  63.   blogService.insertBlogList(blogList);
  64.   // 删除数据
  65.   try {
  66.     blogService.deleteBlogByCondition(parameter);
  67.   } catch (Exception e) {
  68.     System.err.printf("Err:%s%n", e.getMessage());
  69.   }
  70.   System.out.println("继续插入数据");
  71.   // 继续插入数据
  72.   blogService.insertBlogList(blogList);
  73.   // 插入和删除都成功
  74. }
复制代码
NESTED

Execute within a nested transaction if a current transaction exists, behave like REQUIRED otherwise.
如果当前已存在事务,则嵌入到当前事务中运行,否则和REQUIRED效果一样。
  1. @Transactional(propagation = Propagation.NESTED)
  2. public void insertBlogList(List<Blog> blogList) {
  3.   for (Blog blog : blogList) {
  4.     this.blogMapper.insertBlog(blog);
  5.   }
  6. }
  7. @Transactional(propagation = Propagation.NESTED)
  8. public void deleteBlogByCondition(BlogSearchParameter parameter) {
  9.   List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  10.   for (Blog blog : blogs) {
  11.     this.blogMapper.deleteBlog(blog.getId());
  12.   }
  13.   // 抛出一个RuntimeException
  14.   throw new RuntimeException("deleteBlogByCondition抛出一个异常");
  15. }
  16. @Transactional
  17. public void insertAndDeleteBlogList1(List<Blog> blogList, BlogSearchParameter parameter) {
  18.   BlogNestedTxService blogService =
  19.       this.applicationContext.getBean(BlogNestedTxService.class);
  20.   // 插入数据
  21.   blogService.insertBlogList(blogList);
  22.   // 删除数据
  23.   blogService.deleteBlogByCondition(parameter);
  24.   // 所有操作都会回滚
  25. }
  26. @Transactional
  27. public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {
  28.   BlogNestedTxService blogService =
  29.       this.applicationContext.getBean(BlogNestedTxService.class);
  30.   // 插入数据
  31.   blogService.insertBlogList(blogList);
  32.   // 删除数据
  33.   try {
  34.     blogService.deleteBlogByCondition(parameter);
  35.   } catch (Exception e) {
  36.     System.err.printf("Err:%s%n", e.getMessage());
  37.   }
  38.   System.out.println("继续插入数据");
  39.   // 继续插入数据
  40.   blogService.insertBlogList(blogList);
  41.   // 前后两次插入操作成功,
  42.   // 中间的删除操作因为抛出异常,会回滚,
  43.   // 又因为blogService.deleteBlogByCondition(parameter)的异常被try...catch了,
  44.   // 没有抛到insertAndDeleteBlogList2中,所以insertAndDeleteBlogList2的操作可以成功提交
  45. }
  46. public void insertAndDeleteBlogList3(List<Blog> blogList, BlogSearchParameter parameter) {
  47.   BlogNestedTxService blogService =
  48.       this.applicationContext.getBean(BlogNestedTxService.class);
  49.   // 插入数据
  50.   blogService.insertBlogList(blogList);
  51.   // 删除数据
  52.   blogService.deleteBlogByCondition(parameter);
  53.   // 插入成功,删除回滚
  54. }
  55. public void insertAndDeleteBlogList4(List<Blog> blogList, BlogSearchParameter parameter) {
  56.   BlogNestedTxService blogService =
  57.       this.applicationContext.getBean(BlogNestedTxService.class);
  58.   // 插入数据
  59.   blogService.insertBlogList(blogList);
  60.   // 删除数据
  61.   try {
  62.     blogService.deleteBlogByCondition(parameter);
  63.   } catch (Exception e) {
  64.     System.err.printf("Err:%s%n", e.getMessage());
  65.   }
  66.   System.out.println("继续插入数据");
  67.   // 继续插入数据
  68.   blogService.insertBlogList(blogList);
  69.   // 插入成功,删除回滚
  70. }
复制代码
小结

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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4