方法A和方法B的事务传播性都为PROPAGATION_REQUIRED 当方法A调用方法B, 方法B报错, 即使报错被外层捕获, 整体事务也会回滚.报错信息为UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
@Override
public void do_transaction_required_required_exception_try ( Integer id, String name) {
this . save ( new Users ( id, name, null) ) ;
try {
biaoSuoService. addBiaoSuo ( id, name) ;
} catch ( Exception e) {
log. error ( "插入记录错误信息" , e) ;
}
}
@Override
public boolean addBiaoSuo ( Integer id, String name) {
BiaoSuo biaoSuo = new BiaoSuo ( ) ;
biaoSuo. setId ( id) ;
biaoSuo. setName ( name) ;
super . save ( biaoSuo) ;
int i = 1 ;
if ( i == 1 ) {
throw new RuntimeException ( "addBiaoSuo方法报错..." ) ;
}
return true ;
}
@Test
public void contextLoads ( ) {
usersService. do_transaction_required_required_exception_try ( 26 , "name26" ) ;
}
测试结果
方法A的事务传播性为PROPAGATION_REQUIRED, 方法B的事务传播性为PROPAGATION_REQUIRES_NEW 当方法A调用方法B, 方法B报错, 报错被外层捕获时, 新开的事务B回滚, 外层的事务A不会回滚.
@Override
public void do_transaction_required_requiresNew_exception_try ( Integer id, String name) {
System. out. println ( "方法是否有事务: " + TransactionSynchronizationManager. isActualTransactionActive ( ) ) ;
this . save ( new Users ( id, name, null) ) ;
try {
biaoSuoService. newTl_requiresNew_exception ( id, name) ;
} catch ( Exception e) {
log. error ( "插入记录错误信息" , e) ;
}
}
@Override
public boolean newTl_requiresNew_exception ( Integer id, String name) {
BiaoSuo biaoSuo = new BiaoSuo ( ) ;
biaoSuo. setId ( id) ;
biaoSuo. setName ( name) ;
super . save ( biaoSuo) ;
log. info ( "isNewTransaction: [{}]" , TransactionAspectSupport. currentTransactionStatus ( ) . isNewTransaction ( ) ) ;
int i = 1 ;
if ( i == 1 ) {
throw new RuntimeException ( "addBiaoSuorequiresNew_exception方法报错..." ) ;
}
return true ;
}
@Test
public void test1 ( ) {
usersService. do_transaction_required_requiresNew_exception_try ( 27 , "name27" ) ;
}
测试结果
方法A的事务传播性为PROPAGATION_REQUIRED, 方法B的事务传播性为NESTED 当方法A调用方法B, 方法B报错, 整体事务会回滚. 如果外层捕获方法B的异常, 只有子事务B会回滚, 方法A不会回滚.
@Override
public void do_transaction_required_nested_exception ( Integer id, String name) {
System. out. println ( "方法是否有事务: " + TransactionSynchronizationManager. isActualTransactionActive ( ) ) ;
this . save ( new Users ( id, name, null) ) ;
biaoSuoService. addNestedException ( id, name) ;
}
@Override
public boolean addNestedException ( Integer id, String name) {
BiaoSuo biaoSuo = new BiaoSuo ( ) ;
biaoSuo. setId ( id) ;
biaoSuo. setName ( name) ;
super . save ( biaoSuo) ;
log. info ( "hasSavepoint: [{}]" , TransactionAspectSupport. currentTransactionStatus ( ) . hasSavepoint ( ) ) ;
int i = 1 ;
if ( i == 1 ) {
throw new RuntimeException ( "addNestedException方法报错..." ) ;
}
return true ;
}
@Test
public void test2 ( ) {
usersService. do_transaction_required_nested_exception ( 29 , "name29" ) ;
}
测试结果
NESTED和REQUIRED的区别与联系 NESTED和REQUIRED修饰的内部方法都属于外围方法事务,如果外围方法抛出异常,这两种方法的事务都会被回滚。但是REQUIRED是加入外围方法事务,所以和外围事务同属于一个事务,一旦REQUIRED事务抛出异常被回滚,外围方法事务也将被回滚。而NESTED是外围方法的子事务,有单独的保存点,所以NESTED方法抛出异常被回滚,不会影响到外围方法的事务。NESTED和REQUIRES_NEW的区别与联系 NESTED和REQUIRES_NEW都可以做到内部方法事务回滚而不影响外围方法事务。但是因为NESTED是嵌套事务,所以外围方法回滚之后,作为外围方法事务的子事务也会被回滚。而REQUIRES_NEW是通过开启新的事务实现的,内部事务和外围事务是两个事务,外围事务回滚不会影响内部事务。一般的用法
我能影响你, 但是你不能影响我. 你应该用NESTED, 我应该捕获你的异常. 日志方法应该使用PROPAGATION_NOT_SUPPORTED
小技巧
事务什么时候会生效? service的实现类上有注解, 并且方法名以事务配置中的前缀开头 如何判断某个有没有事务? TransactionSynchronizationManager.isActualTransactionActive() 如何获取到当前方法的事务? TransactionAspectSupport.currentTransactionStatus(); 编程式事务如何实现? TransactionTemplate或者PlatformTransactionManager 服务经常报获取不到数据库连接怎么办? 检查编程式事务有没有提交或回滚事务, 防止数据库连接泄漏. 如果事务只对后端的数据库进行该操作,数据库可以利用事务的只读特性来进行一些特定的优化。
注意事项
@Transactional 只能被应用到 public 方法上,对于其它非 public 的方法,如果标记了 @Transactional 也不会报错,但方法没有事务功能。 Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。 默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚.