从@Transactional注解看Spring事务

        在使用Spring事务时,我们只需在某方法上使用@Transactional注解简单的标注一下,便可以实现很强大的事务控制功能,这其中的缘由,看小编娓娓道来;

         首先需要明确:在spring事务的切面中,实际上是一个Around切面,在注解的业务方法前后都可以被调用,而实际上实现切面操作的是TransactionInterceptor类;

[本篇我们先从实例代码看该注解]

1)在代码中使用@Transactional 注解,不设置事务的其他属性,默认只对RuntimeException和Error进行回滚:

@Transactional
public void rollback() throws SQLException {
    // update db
    throw new SQLException("exception");
}

事实证明:上述的代码并不会回滚;

2)对于需要回滚的异常,需要在注解中设置rollbackFor属性,但这时,对于RuntimeException和Error的异常依旧会回滚:

@Transactional(rollbackFor = {SQLException.class})
public void rollback() throws SQLException {
    // update db
    throw new RuntimeException("exception");
}

在上述代码片段中,虽然指定了SqlException,但方法体中的RuntimeException依旧会造成事务回滚;

3)嵌套事务

@Transactional
public void rollback() {
    // updateA
    try{
        selfProxy.innelTransaction()
    }catch(RuntimeException e){
        //do nothing
    }
    //updateC
}
  
@Transactional
public void innelTransaction() throws SQLException {
    // updateB
    throw new RuntimeException("exception");
}

在上述代码中,innerTransaction方法中的异常并未拦截,在被rollback方法拦截之前,AOP已经获取了异常,此时,当前事务的readOnly会被设置为true,所以即使在rollback方法中进行了拦截和处理,代码依旧会造成事务回滚;

产生以上现象的原因:

  内部方法(innelTransaction)抛出异常,触发了回滚,这时当前事务被设置为 rollback-only,当外部方法所在的事务提交时,Spring抛出以下异常,同时会将当前事务回滚;

org.springframework.transaction.UnexpectedRollbackException: 
           Transaction rolled back because it has been marked as rollback-only

在上述代码中:

即使innelTransaction方法不加事务处理,依旧会有这个异常;

原因:在外部方法中,使用了一个事务,当内部方法抛出异常时,事务会被标记为需要回滚,但是最终要在外部方法的事务提交时,校验,spring的回滚标志,检测到回滚标记就会在回滚事务,并抛出UnexceptedRollbackException;

 

若要控制上述代码不做回滚

1)我们需要在内部方法体中,将异常捕获,通过Boolean返回值的方式来完成;

2)使用ServiceB的代理类来完成对functionB 的调用

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值