Spring中的@Transactional
注解是我们在项目中经常使用的,但如果不了解其实现原理,容易在使用过程中产生BUG.
关于这个注解(其实也包括很多类似的注解),最重要的是知道,这个注解功能的实现是用了AOP,也就是代理来实现的。
@Transactional 使用代理来实现。通过静态织入或者动态织入生成代理类,在调用真实对象的方法前后进行一些额外的操作。
它的代理类实现大概长这样子:
UserTransaction utx = entityManager.getTransaction();
try {
utx.begin();
businessLogic();
utx.commit();
} catch(Exception ex) {
utx.rollback();
throw ex;
}
有了这个概念之后,我们就能解释很多事情。
01
@Transactional 注解只能应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。
由于生成的代理类需要访问真实对象的方法,真实对象中的方法需要设置为public
,否则代理类无法访问真实对象。
02
在同一个类中,一个方法调用另外一个有注解(比如@Async,@Transational)的方法,注解是不会生效的。
示例代码如下:
class A {
public void service() {
anotherService();
}
@Transactional
public void anotherService() {
myBusiness();
}
}
service方法没有事务,它调用了一个有事务的anotherService方法,那么这时anotherService会开启事务吗?答案是不会。因为这里已经执行到调用真实对象的方法的时刻,这时的anotherService();
其实是调用this.anotherService();
,而不是调用代理类的anotherService方法,因而会忽略注解,注解并没有起到作用。
03
"Transaction rolled back because it has been marked as rollback-only" 异常。
这是一个很常见的异常,也是我遇见的第一个关于spring事务的异常。
下面这段代码会报异常吗?
@Transactional
public void add(Member member) {
try {
operateLogService.add(entity); // 抛出运行时异常
} catch (Exception e) {
e.printStackTrace();
}
}
答案是会。因为执行operateLogService.add方法抛出了运行时异常,spring会设置事务的rollback only
标志为true,处理完异常后整个add方法没有抛出异常,如上面所述,会执行utx.commit()
动作,但发现marked as rollback-only,所以无法提交。
再看一个例子:
@Transactional
public void add(Member member) {
try {
operateLogService.add(entity); // 抛出运行时异常
} catch (Exception e) {
other.save(); // 执行其他修改数据库的操作
e.printStackTrace();
}
}
这个例子比上个例子多了一个数据库修改操作,那么这时也会抛出rollback-only异常。道理也是一样的,执行other.save时需要commit,但rollback-only为true,不能提交。
有人可能会问,这么设计的原因是什么呢?在我看来,是为了知晓事务的状态。如果上面两种情况都不报异常的能够顺利commit的话,那么add(member)
事务到底执行成功与否我是无法判断的。现在事务执行失败报了rollback-only异常,事务执行成功则不报异常,这正是大多数人所需要的。
最后一点,spring默认只有抛出RuntimeException时才进行回滚。
Reference:
http://blog.jhades.org/how-does-spring-transactional-really-work/
https://stackoverflow.com/questions/18590170/transactional-does-not-work-on-method-level
http://blog.csdn.net/clementad/article/details/47339519
http://www.importnew.com/19489.html