@Transactional事务几点注意

这里面有几点需要大家留意:
A. 一个功能是否要事务,必须纳入设计、编码考虑。不能仅仅完成了基本功能就ok。
B. 如果加了事务,必须做好开发环境测试(测试环境也尽量触发异常、测试回滚),确保事务生效。
C. 以下列了事务使用过程的注意事项,请大家留意

  1. 不要在接口上声明@Transactional ,而要在具体类的方法上使用 @Transactional 注解,否则注解可能无效。
  2. 不要图省事,将@Transactional放置在类级的声明中,放在类声明,会使得所有方法都有事务。故@Transactional应该放在方法级别,不需要使用事务的方法,就不要放置事务,比如查询方法。否则对性能是有影响的。
  3. 使用了@Transactional的方法,对同一个类里面的方法调用, @Transactional无效。比如有一个类Test,它的一个方法A,A再调用Test本类的方法B(不管B是否public还是private),但A没有声明注解事务,而B有。则外部调用A之后,B的事务是不会起作用的。(经常在这里出错)
  4. 使用了@Transactional的方法,只能是public,@Transactional注解的方法都是被外部其他类调用才有效,故只能是public。道理和上面的有关联。故在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错,但事务无效
  5. 经过在ICORE-CLAIM中测试,效果如下:
  • 抛出受查异常XXXException,事务会回滚。
  • 抛出运行时异常NullPointerException,事务会回滚。
  • Quartz中,execute直接调用加了@Transactional方法,可以回滚;间接调用,不会回滚。(即上文3点提到的)
  • 异步任务中,execute直接调用加了@Transactional方法,可以回滚;间接调用,不会回滚。(即上文3点提到的)
  • 在action中加上@Transactional,不会回滚。切记不要在action中加上事务。
  • 在service中加上@Transactional,如果是action直接调该方法,会回滚,如果是间接调,不会回滚。(即上文3提到的)
    G.在service中的private加上@Transactional,事务不会回滚。

其属性Propagation的使用:

Spring Transaction中有一个很重要的属性:Propagation。主要用来配置当前需要执行的方法,与当前是否有transaction之间的关系。

我晓得有点儿抽象,这也是为什么我想要写这篇博客的原因。看了后面的例子,大家应该就明白了。

一、Propagation取值:

REQUIRED(默认值):在有transaction状态下执行;如当前没有transaction,则创建新的transaction;
SUPPORTS:如当前有transaction,则在transaction状态下执行;如果当前没有transaction,在无transaction状态下执行;
MANDATORY:必须在有transaction状态下执行,如果当前没有transaction,则抛出异常IllegalTransactionStateException;
REQUIRES_NEW:创建新的transaction并执行;如果当前已有transaction,则将当前transaction挂起;
NOT_SUPPORTED:在无transaction状态下执行;如果当前已有transaction,则将当前transaction挂起;
NEVER:在无transaction状态下执行;如果当前已有transaction,则抛出异常IllegalTransactionStateException。

二、REQUIRED与REQUIRED_NEW
上面描述的6种propagation属性配置中,最难以理解,并且容易在transaction设计时出现问题的是REQUIRED和REQURED_NEW这两者的区别。当程序在某些情况下抛出异常时,如果对于这两者不够了解,就可能很难发现而且解决问题。

下面我们给出三个场景进行分析:

场景一:

ServiceA.java:
public class ServiceA {@Transactionalpublic void callB() {serviceB.doSomething();}
}
ServiceB.java
public class ServiceB {@Transactionalpublic void doSomething() {throw new RuntimeException("B throw exception");}
}

这种情况下,我们只需要在调用ServiceA.callB时捕获ServiceB中抛出的运行时异常,则transaction就会正常的rollback

场景二

在保持场景一中ServiceB不变,在ServiceA中调用ServiceB的doSomething时去捕获这个异常,如下:

public class ServiceA {@Transactionalpublic void callB() {try {serviceB.doSomething();} catch (RuntimeException e) {System.err.println(e.getMessage());}}
}

这个时候,我们再调用ServiceA的callB。程序会抛出org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only这样一个异常信息。原因是什么呢?
因为在ServiceA和ServiceB中的@Transactional propagation都采用的默认值:REQUREID。根据我们前面讲过的REQUIRED特性,当ServiceA调用ServiceB的时候,他们是处于同一个transaction中。如下图所示:

当ServiceB中抛出了一个异常以后,ServiceB会把当前的transaction标记为需要rollback。但是ServiceA中捕获了这个异常,并进行了处理,认为当前transaction应该正常commit。此时就出现了前后不一致,也就是因为这样,抛出了前面的UnexpectedRollbackException。

场景三

在保持场景二中ServiceA不变,修改ServiceB中方法的propagation配置为REQUIRES_NEW,如下:

public class ServiceB {@Transactional(propagation = Propagation.REQUIRES_NEW)public void doSomething() {throw new RuntimeException("B throw exception");}
}

此时,程序可以正常的退出了,也没有抛出UnexpectedRollbackException。原因是因为当ServiceA调用ServiceB时,serviceB的doSomething是在一个新的transaction中执行的。如下图所示:

所以,当doSomething抛出异常以后,仅仅是把新创建的transaction rollback了,而不会影响到ServiceA的transaction。ServiceA就可以正常的进行commit。
当然这里把ServiceA和ServiceB放在两个独立的transaction是否成立,还需要再多多考虑你的业务需求。

@Transactional和Propagation的使用相关推荐

  1. Spring Boot 中使用 @Transactional 注解配置事务管理

    From: https://blog.csdn.net/nextyu/article/details/78669997 事务管理是应用系统开发中必不可少的一部分.Spring 为事务管理提供了丰富的功 ...

  2. @Transactional之Spring事务深入理解

         Spring支持两种事务方式: 编程式事务:使用的是TransactionTemplate(或者org.springframework.transaction.PlatformTransac ...

  3. @Transactional 使用说明

    一.说明 @Tranasctional注解是Spring 框架提供的声明式注解事务解决方案,我们在开发中使用事务保证方法对数据库操作的原子性,要么全部成功,要么全部失败,在使用@Transaction ...

  4. @Transactional子事务单独提交

    需求是在添加了事务的service方法内,执行一个单独事务的添加方法,service报错等导致数据回滚时,单独事务的方法不回滚. 单独提交方法需要放在不用的服务类里,使用Transactional的p ...

  5. @Transactional详解及其实现步骤

    转载至 刘万振 @Transactional 注解管理事务的实现步骤 使用@Transactional 注解管理事务的实现步骤分为两步.第一步,在 xml 配置文件中添加如清单 1 的事务配置信息.除 ...

  6. Spring事务注解Transactional失效

    前情提要:当Service接口实现类中存在内部方法调用,并且方法需要支持事务控制时,事务控制失效,事务的传播级别为默认REQUIRED(默认模式). 1.简化版翻车代码: Service接口层 Ser ...

  7. spring transactional

    事务的实现原理 事务的实现原理.如果说你加了一个 @Transactional 注解,此时 Spring 会使用 AOP 思想,对你的这个方法在执行之前,先去开启一个事务.执行完毕之后,根据你的方法是 ...

  8. @Transactional

    一.作用于接口.接口方法.类以及类方法上 1️⃣当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性. 2️⃣当作用在方法级别时会覆盖类级别的定义. 3️⃣当作用在接口和接口方法时则 ...

  9. hibernate3

    hibernate3 (整合到spring中的core核心配置中的hibernate3) <!-- 基于hibernate的Session工厂 --><bean id="s ...

最新文章

  1. GlideApp 引入不了问题
  2. LinearAlgebra_1
  3. 实战并发编程 - 06线程在执行过程中的状态是如何流转的
  4. c++ 和 C语言 中数组语法的比较
  5. IDEA 2020 本土化,真的是全中文了,新手,开心了!
  6. Winform中实现点击按钮弹窗输入密码验证通过后执行相应逻辑
  7. 一键清除Delphi中无用的文件
  8. sklearn朴素贝叶斯分类器_朴素贝叶斯原理
  9. 【鬼网络】之PXE高效批量网络装机
  10. python有没有三元运算符_Python基础入门:从变量到异常处理(1)
  11. 图解elasticsearch原理转载自
  12. Creating Options Pages
  13. Java题目:一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?
  14. Axure RP从入门到精通(一)原型设计工具简介
  15. 程序员5种编程入门方法,如何快速学会一门编程语言?
  16. 广义线性模型(GLM)初级教程
  17. TCR历史研究夏校申请详解
  18. tensor之维度转换
  19. 快速识别无效数据(数据有效性/数据验证)
  20. 2019江西(南昌)安博会 数字冰雹“警视”即将惊艳亮相

热门文章

  1. leetcode292. Nim 游戏(java python3)
  2. 只需要高中数学知识就可以入门计算机图形学啦
  3. 计算机一级字幕设置,电脑pptv怎么设置调整字幕位置大小字体和颜色?
  4. 有关 Mybatis 中使用el表达式问题
  5. MATLAB之机器学习——RBF神经网络
  6. 自动生成拼音(汉字反查到拼音)
  7. mysql datetime类型精确到毫秒、微秒的问题
  8. 红楼梦 —— 人物关系谱
  9. 客服系统必备功能推荐
  10. 最详细的Git原理总结+如何解决冲突