资讯专栏INFORMATION COLUMN

@Transactional事务生效问题

tomorrowwu / 1473人阅读

摘要:情况一方法方法强制抛一个异常情况一就是这样,方法里面顺序调用两个方法,方法不加事务注解,方法加了事务注解。如果不了解事务的传播性,可能会回答成功插入,插入失败但是实际情况却是均插入成功了。

平时我们使用spring框架,不论是springmvcv还是springboot,springCloud,绝大多数情况我们都是在方法,或者直接在类上面加一个@Transactional,将事务交给spring替我们去管理,然后并没有具体分析一些情况,今天结合几个例子,结合源代码,使用伪代码解释一波。

1.情况一
   service(){
       //方法A
       methodA(){
           insertA();
       }
       //方法B
       @Transactional
       methodB(){
           insertB();
           throw new RunTimeException("强制抛一个异常");
       }
       public void static main(String[] args){
           methodA();
           methodB();
       }
   }

情况一就是这样,main方法里面顺序调用AB两个方法,A方法不加事务注解,B方法加了事务注解。如果不了解@Transactional 事务的传播性,可能会回答:A成功插入,B插入失败,但是实际情况却是A,B均插入成功了。到底是什么原因呢?这里先简单介绍一下事务的6个传播属性:

PROPAGATION_REQUIRED : 支持当前事务,如果当前没有事务,就新建一个事务,这也是最常见的
PROPAGATION_SUPPORTS : 支持当前事务,如果当前没有事务,就以非事务的方式执行
PROPAGATION_MANDATORY: 支持当前事务,如果当前没有事务,就抛异常
PROPAGATION_REQUIRES_NEW:新建事务,如果当前事务存在,就把当前事务挂起
PROPAGATION_NOT_SUPPORTED:以非事务的方式执行,如果存在当前事务,就把当前事务挂起
PROPAGATION_NEVER: 以非事务的方式执行,如果当前存在事务,就抛异常
PROPAGATION_NESTED:如果存在当前事务,则在嵌套事务内执行,如果当前没有事务,则新建一个事务

前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。

研究源码,调试程序可以看到:
A没有事务管理,则线程内的connection 有个autoCommit = true
B得到事务的时候,由于事务的传播性依然生效, 得到的还是A方法的commit,其autoCommit = true,故而逐条sql进行提交,即A,B都会插入

下面我们来分析情况二:
serviceA(){
    methodA(){
        insertA();
    }
} 
serviceB(){
    @Transactional
    methodB(){
        insertB();
        throw new RuntimeExcption("强制抛出的异常");
    }
}
serviceC(){
    @Autowired
    private ServiceA serviceA;
    @Autowired
    private ServiceB serviceB;

    public void staic main(String[] args){
        serviceA.methodA();
        serviceB.methodB();
    }
}


情况二的主要代码和情况一一样,都是要调用methodA和methodB,但是结果却不同,情况二的正确结果是指挥插入A,而B会回滚,这是为什么呢?同样是在B方法上面加了事务注解....

其实大家都知道,spring的事务是交由cglib动态代理的,而动态代理对象产生的时机就非常重要了。再回到本例子:

A:在同一个service内部,事务之间嵌套调用,普通方法和事务方法之间的嵌套调用,都不会开启新的事务(因为shpring使用的是动态代理的方式来控制的事务,而动态代理最终都是要调用原始对象的,而原始对象在调用方法时,已存在代理对象,是不会再触发代理了!)
B:两个方法在不同的service里(即不同的对象,即代理对象也不是同一个),在ServiceC中,使用注入的方式将serviceA和serviceB注入,这样即使A没有使用事务,B也有自己的代理,会根据PROPAGATION_REQUIRED 而生成新的事务.

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73590.html

相关文章

  • 【Spring】一次线上@Transational事务注解未生效的原因探究

    摘要:由于的限制,无法替换被代理类已经被载入的字节码,只能生成并载入一个新的子类作为代理类,被代理类的字节码依然存在于中。区别于前两者,是一种静态代理的实现,即在编译时或者载入类时直接修改被代理类文件的字节码,而非运行时实时生成代理。 现象描述 上周同事发现其基于mySql实现的分布式锁的线上代码存在问题,代码简化如下: @Controller class XService { @A...

    姘存按 评论0 收藏0
  • Spring 踩坑之@Transactional 神奇失效

    摘要:引言对于追求数据强一致性的系统,事务扮演者十分重要的角色最近在项目中遇到一个事务失效的问题,在此分享给大家。情景回放问题分析初步分析这是事务获取锁超时导致的错误,奇怪的是抛出异常但是事务没有回滚。唯一的解释是事务失效了。 引言 对于追求数据强一致性的系统,事务扮演者十分重要的角色.最近在项目中遇到一个事务失效的问题,在此分享给大家。 情景回放 ### Cause: com.mysql....

    derek_334892 评论0 收藏0
  • 面试分享:最全Spring事务面试考点整理

    摘要:和事务的关系关系型数据库某些消息队列等产品或中间件称为事务性资源,因为它们本身支持事务,也能够处理事务。事务的传播特性,,,,,,强制要求要有一个物理事务。外围事务不会被内部事务的回滚状态影响。不支持当前事务。 Spring和事务的关系 关系型数据库、某些消息队列等产品或中间件称为事务性资源,因为它们本身支持事务,也能够处理事务。 Spring很显然不是事务性资源,但是它可...

    graf 评论0 收藏0
  • spring事务处理

    摘要:声明式事务管理的事务管理是通过代理实现的。其中的事务通知由元数据目前基于或注解驱动。代理对象与事务元数据结合产生了一个代理,它使用一个实现品配合,在方法调用前后实施事务。 JDBC事务 1.获取连接 Connection con=DriverManager.getConnection(); 2.开启事务 con.setAutoCommit(true/fase); 3.执行CRUD 4....

    李文鹏 评论0 收藏0
  • 在同一个类中调用另一个方法没有触发 Spring AOP 的问题

    摘要:起因考虑如下一个例子定义在这个例子中我们定义了一个注解这个是一个方法注解我们的期望是当有此注解的方法被调用时需要执行指定的切面逻辑即执行方法在类中方法被所注解因此调用方法时应该会触发方法的调用不过有一点我 起因 考虑如下一个例子: @Target(value = {ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Doc...

    yimo 评论0 收藏0

发表评论

0条评论

tomorrowwu

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<