@Transactional注解常见的坑

@Transaction注解失效

1、加@Transaction的方法必须是public,否则失效
2、在同一个类里,两个@Transaction方法直接嵌套调用会失效

A方法调用B方法,B方法加上@Transaction注解,如果A,B方法在同一个类里,则方法B的@Transaction注解失效。
因为@Transaction注解实现原理是AOP,自身调用不会产生代理对象,AOP无法织入,所以会失效。
解决方法:将A,B方法放在两个类中,或是使用AopContext.currentProxy()
https://blog.csdn.net/qq_38085240/article/details/87801025
3、绕过springboot的DataSource获取的数据库连接,事务管理器需要手动配置,否则失效
4、Spring是通过TransactionSynchronizationManager类中的ThreadLocal变量来获取事务中的数据库连接,所以如果是多线程调用失效
5、如果类和方法上同时加上@Transaction注解,方法上的定义优先
6、以下这种场景

如果在加了事务注解的A方法中,调用B方法,B方法有异常,则分为B有事务注解和没有事务注解两种情况:
6.1 方法B没有事务
如果方法B中没有事务注解,则由于方法A已经catch住了异常,所以方法A上的事务并不会感知到异常,所以方法不会回滚,并且如果方法B的数据库操作也能顺利写入
6.2 方法B有事务
如果方法B有事务,如果默认的传播行为,require,则TransactionState对象会传递到方法B上,所以会将整个TransactionState对象的rollback属性设定为true,所以A方法也会回滚,即是在方法A中catch了异常也无用。
这里值得一提的一点是,这里TransactionDefinition会以方法B上定义的为准,如果B上的传播特性为require_new,由于新创建了一个TransactionState,则不会影响A。
如果方法B的事务注解上配置了noRollbackFor,如果是满足条件的异常则不会影响A。

事务超时

Spring事务超时判断只是在执行数据库操作时候,所以如果超时后没有数据库操作,则无法准确超时。

    @Transactional(timeout = 5)
    public void timeout() throws InterruptedException {
        Thread.sleep(1000000);
        insert();//会报超时异常
    }

    @Transactional(timeout = 5)
    public void timeout() throws InterruptedException {
        insert();
        Thread.sleep(1000000);//这个方法不会超时异常,因为超时后没有数据库操作
    }
posted @ 2020-11-16 19:50  刃牙  阅读(3240)  评论(0编辑  收藏  举报