spring-tx概述
spring-tx包使用注解驱动和AOP通知将事务开启、提交/回滚、以及复杂的传播机制封装了起来,开发者不再需要编写事务管理的代码,而是可以只关注自己的业务逻辑。
本文将简单介绍spring-tx使用步骤以及七种事务传播级别。
后续文章会阅读源码,深入分析spring-tx aop通知、七种事务传播级别以及事务开启/提交/回滚的实现方式。
使用步骤
- 导入spring-tx依赖
- 使用@EnableTransactionManagement注解为应用开启事务支持
- 向spring容器注入一个TransactionManager实现,一般使用DataSourceTransactionManager类
- 在需要事务的业务方法上标注@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.
支持当前存在的事务,如果当前没有事务,则新创建一个。默认的传播级别。REQUIRES_NEW
Create a new transaction, and suspend the current transaction if one exists.
创建新事务,如果当前已存在事务则挂起这个事务,再打开一个新的数据库连接创建新事务。MANDATORY
Support a current transaction, throw an exception if none exists.
支持当前存在的事务,如果当前没有事务,则抛出异常。SUPPORTS
Support a current transaction, execute non-transactionally if none exists.
支持当前存在的事务,如果当前没有事务,则在无事务状态下运行。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的实现方式。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |