Java小强个人技术博客站点    手机版
当前位置: 首页 >> 框架 >> Spring事物不生效的原因

Spring事物不生效的原因

34581 框架 | 2021-5-20

在维护一个之前搭建的框架,SpringMVC框架,看着所有的配置都正常,而且也一直在使用,可是当我编写好代码时突然想到,我的逻辑里面要插入好几次SQL,这里面的事物是否管用呢?

于是我测试了一下,竟然是不起作用。改配置,加注解,各种操作都试了,aop:config和tx:advice配置看着都对,可事物就是不起作用。


偶然间看到网上有人说context:component-scan配置不当会引起事物不起作用,看了一下,果然,该框架扫描直接在SringMVC配置文件中写了一个根路径。


于是修改SpringMVC只扫描Controller包

<context:component-scan base-package="com.csq.action"/>

Spring配置扫描所有包但是拍出Controller包

<context:component-scan base-package="com.jlc">
	<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>


其他不动,测试事物已经生效。


如果是那种分模块的包,比如A模块下面分了action,service,dao,然后B、C。。。模块都是这样,怎么扫描呢?

<context:component-scan>提供两个子标签:<context:include-filter><context:exclude-filter>各代表引入和排除的过滤。

<!-- 排除controller注解支持 -->
<context:component-scan base-package="com.test">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

<!-- 开启controller注解支持 -->
<context:component-scan base-package="com.b505.web">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>


根据这次问题,总结了可能出现此类问题的原因,仅供参考:

(1)事务方法内部捕捉了异常,没有抛出新的异常,导致事务操作不会进行回滚。

(2)在类内部调用调用类内部@Transactional标注的方法。这种情况下也会导致事务不开启。

(3)Transactional注解标注方法修饰符为非public时,@Transactional注解将会不起作用。

(4)数据库本身对应的库、表所设置的引擎是什么。MyIsam不支持事务,如果需要,则必须改为InnnoDB。

(5)@Transactional所注解的方法所在的类,是否已经被注解@Service或@Component等。

(6)注解为事务范围的方法中,事务的回滚仅仅对于unchecked的异常有效。对于checked异常无效。也就是说事务回滚仅仅发生在出现RuntimeException或Error的时候。如果希望一般的异常也能触发事务回滚,需要在注解了@Transactional的方法上,将@Transactional回滚参数设为:

@Transactional(rollbackFor=Exception.class)


崔素强博客

END

推荐您阅读更多有关于“ controller 注解 springmvc context Transactional ”的文章

上一篇:ZXing生成和解析二维码 下一篇:定制js的alert和confirm

猜你喜欢

发表评论:

评论:

回复 Java小强 评论于 2022-01-22 22:07
黑马程序员,Java面试题视频教程中提取的,关于Spring事物不起作用的原因:

(1)没有处理检查异常,比如FileNotFindException,Spring默认只回滚非检查异常
在@Transactional注解添加rollbackFor=Exception。

(2)自己处理try-catch导致Spring无法获知异常
异常向上抛出,或者手动设置TransactionInterceptor.currentTransactionStatus.setRollbackOnly()。

(3)自定义AOP切面顺序
默认自己写一个切面的优先级和事物是一样的,都是最低,但是Spring默认先执行事物的再执行自定义的,如果自定义切面中出现(2)情况事物失效。
切面中处理参考(2),或者调整切面顺序,让自定义切面优先级高于Spring事物切面。

(4)非public方法
默认Spring为方法创建代理,添加事物通知,前提都是该方法都是public的。

(5)父子容器导致,子容器扫描范围过大
各自扫描各自的包,或者不要使用父子容器。
如果使用了SpringMVC,SpringMVC只扫描Controller包。

(6)Spring事物传播行为配置不当
如果同一个service中A使用this调用方法B,这时B上的事物注解无效。
方法B提取到不同的service中,也可以在本service中注入自己然后通过该对象进行调用。或者通过spring获取当前代理对象来调用((ABService)AopContext.currentProxy()).B()但是要配置exposeProxy=true。也可以通过CTW或LTW实现功能增强。

(7)多线程情况下@Transactional没有保证原子性
事物原子性覆盖insert,update,delete,select...for update语句,select方法不堵塞,因此在一个更新没有提交时,再次查询到的是之前数据。因此要在查询时使用for update来堵塞其他线程对该数据的任何操作。

(8)@Transactional方法导致的synchronized失效
synchronized保证了目标方法原子性,但是spring事物的环绕commit等操作并不能保证,因为他们不在sync块内。因此sync要加载代理方法调用之前,比如在Controller内调用时就加。或者使用(7)方法来解决。