赞
踩
因为@Transactional直接加在类或者接口上,@Transactional注解会对类或者接口里面所有的public方法都有效(相当于所有的public方法都加上了@Transactional注解,而且注解带的参数都是一样的)。第一影响性能,可能有些方法我不需要@Transactional注解,第二方法不同可能@Transactional注解需要配置的参数也不同,比如有一个方法只是做查询操作,那咱们可能需要配置Transactional注解的readOnly参数。所以强烈建议@Transactional注解直接添加的需要的方法上。
2. @Transactional 注解必须添加在public方法上,private、protected方法上是无效的:
在使用@Transactional 的时候一定要记住,在private,protected方法上添加@Transactional 注解不会有任何效果。相当于没加一样。即使外部能调到protected的方法也无效。和没有添加@Transactional一样。
3. 同一个类中函数相互调用
情况0: aFunction添加了@Transactional注解,aInnerFunction函数没有添加。aInnerFunction抛异常。
public class AClass {
@Transactional(rollbackFor = Exception.class)
public void aFunction() {
//todo: 数据库操作A(增,删,该)
aInnerFunction(); // 调用内部没有添加@Transactional注解的函数
}
private void aInnerFunction() {
//todo: 操作数据B(做了增,删,改 操作)
throw new RuntimeException("函数执行有异常!");
}
}
结果两个函数都会回滚。
情况1:两个函数都添加了@Transactional注解。aInnerFunction抛异常。
public class AClass {
@Transactional(rollbackFor = Exception.class)
public void aFunction() {
//todo: 数据库操作A(增,删,该)
aInnerFunction(); // 调用内部没有添加@Transactional注解的函数
}
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
private void aInnerFunction() {
//todo: 操作数据B(做了增,删,改 操作)
throw new RuntimeException("函数执行有异常!");
}
}
结果:同第一种情况一样,两个函数对数据库操作都会回滚。因为同一个类中函数相互调用的时候,内部函数添加@Transactional注解无效。@Transactional注解只有外部调用才有效。
情况2: aFunction不添加注解,aInnerFunction添加注解。aInnerFunction抛异常。
public class AClass {
public void aFunction() {
//todo: 数据库操作A(增,删,该)
aInnerFunction(); // 调用内部没有添加@Transactional注解的函数
}
@Transactional(rollbackFor = Exception.class)
protected void aInnerFunction() {
//todo: 操作数据B(做了增,删,改 操作)
throw new RuntimeException("函数执行有异常!");
}
}
结果:两个函数对数据库的操作都不会回滚。因为内部函数@Transactional注解添加和没添加一样。
情况3:aFunction添加了@Transactional注解,aInnerFunction函数没有添加。aInnerFunction抛异常,不过在aFunction里面把异常抓出来了。
public class AClass { @Transactional(rollbackFor = Exception.class) public void aFunction() { //todo: 数据库操作A(增,删,该) try { aInnerFunction(); // 调用内部没有添加@Transactional注解的函数 } catch (Exception e) { e.printStackTrace(); } } private void aInnerFunction() { //todo: 操作数据B(做了增,删,改 操作) throw new RuntimeException("函数执行有异常!"); } }
结果:两个函数里面的数据库操作都成功。事务回滚的动作发生在当有@Transactional注解函数有对应异常抛出时才会回滚。(当然了要看你添加的@Transactional注解有没有效)。
4、不同类中函数相互调用
情况0:aFunction添加注解,bFunction不添加注解。bFunction抛异常。
@Service() public class AClass { private BClass bClass; @Autowired public void setbClass(BClass bClass) { this.bClass = bClass; } @Transactional(rollbackFor = Exception.class) public void aFunction() { //todo: 数据库操作A(增,删,该) bClass.bFunction(); } } @Service() public class BClass { public void bFunction() { //todo: 数据库操作A(增,删,该) throw new RuntimeException("函数执行有异常!"); } }
结果:两个函数对数据库的操作都回滚了。
情况1:aFunction、bFunction两个函数都添加注解,bFunction抛异常。
@Service() public class AClass { private BClass bClass; @Autowired public void setbClass(BClass bClass) { this.bClass = bClass; } @Transactional(rollbackFor = Exception.class) public void aFunction() { //todo: 数据库操作A(增,删,该) bClass.bFunction(); } } @Service() public class BClass { @Transactional(rollbackFor = Exception.class) public void bFunction() { //todo: 数据库操作A(增,删,该) throw new RuntimeException("函数执行有异常!"); } }
结果:两个函数对数据库的操作都回滚了。两个函数里面用的还是同一个事务。这种情况下,你可以认为事务rollback了两次。两个函数都有异常。
情况2:aFunction、bFunction两个函数都添加注解,bFunction抛异常。aFunction抓出异常。
@Service() public class AClass { private BClass bClass; @Autowired public void setbClass(BClass bClass) { this.bClass = bClass; } @Transactional(rollbackFor = Exception.class) public void aFunction() { //todo: 数据库操作A(增,删,该) try { bClass.bFunction(); } catch (Exception e) { e.printStackTrace(); } } } @Service() public class BClass { @Transactional(rollbackFor = Exception.class) public void bFunction() { //todo: 数据库操作A(增,删,该) throw new RuntimeException("函数执行有异常!"); } }
结果:两个函数数据库操作都没成功。而且还抛异常了。org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only。看打印出来的解释也很好理解把。咱们也可以这么理解,两个函数用的是同一个事务。bFunction函数抛了异常,调了事务的rollback函数。事务被标记了只能rollback了。程序继续执行,aFunction函数里面把异常给抓出来了,这个时候aFunction函数没有抛出异常,既然你没有异常那事务就需要提交,会调事务的commit函数。而之前已经标记了事务只能rollback-only(以为是同一个事务)。直接就抛异常了,不让调了。
情况3:aFunction、bFunction两个函数都添加注解,bFunction抛异常。aFunction抓出异常。这里要注意bFunction函数@Transactional注解我们是有变化的,加了一个参数propagation = Propagation.REQUIRES_NEW,控制事务的传播行为。表明是一个新的事务。其实咱们情况3就是来解决情况2的问题的。
@Service() public class AClass { private BClass bClass; @Autowired public void setbClass(BClass bClass) { this.bClass = bClass; } @Transactional(rollbackFor = Exception.class) public void aFunction() { //todo: 数据库操作A(增,删,该) try { bClass.bFunction(); } catch (Exception e) { e.printStackTrace(); } } } @Service() public class BClass { @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class) public void bFunction() { //todo: 数据库操作A(增,删,该) throw new RuntimeException("函数执行有异常!"); } }
结果:bFunction函数里面的操作回滚了,aFunction里面的操作成功了。有了前面情况2的理解。这种情况也很好解释。两个函数不是同一个事务了。
注解只有在抛出RuntimeException 或者是Erroe时从才会触发事务的回滚,常见的非RuntimeException是不会触发事务的回滚的。
但是我们平时做业务处理时,需要捕获异常,即在方法中使用try{}catch(Exception e){},此时在方法上在使用@Transactional注解, 方法出现异常也不会进行回滚。
同理 在其他文章或是解答中有建议使用@Transactional(rollbackFor = Exception.class) 进行事务的回滚,亲测此方法也是不行的,如果你的方法中有使用到了其他异常或是自定义的异常,同样事务也是不会回滚的。
最后的解决方法是在catch中进行手动的事务回滚。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。