日常踩坑_添加了@Transactional注解后,事务不生效

故事梗概

事情是这样的,在使用Jpa的saveAll方法的时候,发现saveAll方法会进行先查询后保存的操作,但我只想要保存,不想要查询
关于saveAll的重写 可以这样用

@PersistenceContext
private EntityManager em;
@Override
public <T> void saveAll(Iterable<T> entities) {
for (T entity : entities) {
em.persist(entity);
}
em.flush();
em.clear();
}

完成了重写之后,发现数据存不进去,而且报错了:No EntityManager with actual transaction available for current thread
这个报错的原因是没有加事务,其实我在saveAll方法上加了@Transactional注解的,但是并没有生效

一般的@Transactional不生效的原因

1、检查你的方法是不是public的,@Transactional注解只能应用到public可见度的方法上,如果应用在protected、private或者package可见度的方法上,也不会报错,不过事务设置不会起作用。
2、检查你的异常类型是不是unchecked异常。默认情况下,Spring会对unchecked异常进行事务回滚,如果是checked异常则不回滚。如空指针异常、算术异常等,会被回滚;文件读写、网络出问题,spring就没法回滚了。如果你想check异常也回滚怎么办,注解上面写明异常类型即可:
like this
@Transactional(rollbackFor = Exception.class)
3、是否在service中进行了try...catch的操作,由于已经被捕获异常,故事务也不会回滚。如果非要在service中try...catch异常,又想要事务回滚,可在catch块中抛出运行时异常

try{
....
}catch(Exception e){
logger.error("",e);
throw new RuntimeException;
}

这种方法有个不足之处,就是不能在catch块中存在return子句,若想捕获异常时回滚事务,同时返回提示信息,可以使用手动回滚:

try{
...
}catch(Exception e){
logger.error("",e);
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return ERROR_MESSAGE;
}

PS:另外说明一下,在controller层捕获了service层的异常,事务还会回滚吗?答案是会的,只要你service层抛出了异常,并且你加的事务可以处理这个异常,也就是rollbackFor = Exception.class这个符合你抛出的异常,不管外面有没有捕获都可以回滚。
4、是否开启了对注解的解析:

<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
id="transactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

5、数据库引擎要支持事务,如果是mysql,注意表要使用支持事务的引擎,比如innodb,如果是myisam,事务是不起作用的。

6、spring是否扫描到你这个包,如下是扫描到org.test下面的包:
<context:component-scan base-package="org.test" ></context:component-scan>

解决

对我来说,以上都没用,哈哈
真实的原因是,@Transactional没加对地方,我把它加在了saveAll的方法上,但实际上我在save()方法中调用了一个create()方法,create()方法中才调用了saveAll()方法
诸位,看清这个关系 save()->create()->saveAll()
那么@Transactional应该加在主方法save()上,而不是下面被调用的方法中

原因是事务可传递,Spring 的事务传播策略在内部方法调用时将不起作用,事务注解加到要调用方法上

ps:注意@Transactional也不要加在接口上,因为spring 采用 aop 针对具体实现类做的代理实现

跳坑完毕,祝你快乐!!

posted @   Dean_001  阅读(1517)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示