记一次实际开发过程中遇到事务报错问题 Transaction synchronization is not active
一:问题场景
在一次http请求的后台接口中返回结果中出现了这个错误信息“Transaction synchronization is not active”,意思是“事务同步器没有激活”,但是被调用的接口已经添加了@Transactional注解,所以百思不得不得其解为什么还会报这个错误,那么是什么原因引起了这个异常呢?自己通过百度大神博客终于找到一篇相似的文章解决了自己的问题,今天就是把解决方案记录下来为以后再出现类似情况提供解决方案。
二:出现原因
Google搜索一番之后,发现了这篇文章Spring的TransactionEventListener,文中提到了可能出现这个错误信息的一种情况:
@EventListener
public void afterRegisterSendMail(MessageEvent event) {
// Spring 4.2 之前
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
internalSendMailNotification(event);
}
});
}
上面的代码将在事务提交后执行.如果在非事务context中(就是方法未开启spring事务)将抛出java.lang.IllegalStateException: Transaction synchronization is not active
于是找到自己代码中的TransactionSynchronizationManager部分,果然在当前http请求链路中的一个接口里发现了类似的代码:
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCommit() {
try {
byte[] bytes = JSON.toJSONBytes(task, new SerializeConfig());
MessageProperties messageProperties = new MessageProperties();
messageProperties.setMessageId(idWorker.nextStringId());
Message message = new Message(bytes, messageProperties);
salaryFileMsgProducer.sendSalaryFileMsg(message);
} catch (Exception e) {
log.error(e.getMessage());
e.printStackTrace();
}
}
});
想必是执行这段代码的时候报的异常,但是上面那篇文章说了引起这个异常的原因是“在非事务context中注册同步器”,难道当前事务没有开启?我们的业务代码一般都是使用spring的注解@Transactional来开启事务,那么去看一下开启事务的代码片段。
三:根本原因
我在调用TransactionSynchronizationManager.registerSynchronization()的方法体上找到了@Transactional注解,方法代码如下,省略具体实现:
@Transactional(rollbackFor = Exception.class)
public Boolean creatSalaryMonthStatistic(SalaryMonthlyStatistic salaryMonthlyStatistic){
....
}
这就奇怪了,明明方法上已经添加@Transactional注解开启事务,为什么事务开启失败,带着这个疑问再次求助了Google,发现了这篇博客spring的service类调用自己方法事务无效,作者也遇到了事务无效的问题,其中总结了事务有效性相关的几点重要信息:
1.在需要事务管理的地方加@Transactional 注解。@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。
2.@Transactional 注解只能应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。
3.注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据。必须在配置文件中使用配置元素,才真正开启了事务行为。(spring配置文件中,开启声明式事务)
4.通过 元素的 “proxy-target-class” 属性值来控制是基于接口的还是基于类的代理被创建。如果 “proxy-target-class” 属值被设置为 “true”,那么基于类的代理将起作用(这时需要CGLIB库cglib.jar在CLASSPATH中)。如果 “proxy-target-class” 属值被设置为 “false” 或者这个属性被省略,那么标准的JDK基于接口的代理将起作用。
5.Spring团队建议在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。在接口上使用 @Transactional 注解,只能当你设置了基于接口的代理时它才生效。因为注解是 不能继承 的,这就意味着如果正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装。
6.@Transactional的事务开启 ,或者是基于接口的 或者是基于类的代理被创建。所以在同一个类中一个无事务的方法调用另一个有事务的方法,事务是不会起作用的。
特别注意第6点:同一个类中一个无事务的方法调用另一个有事务的方法,事务是不会起作用的。这一点引起了我的注意,可能我的加了注解@Transactional的creatSalaryMonthStatistic方法也是被类里另一个没有开启事务的方法调用,如果真的是这样,所有一切都解释的通了。所以带着这个思路检查了一遍自己的代码,
果然,creatSalaryMonthStatistic方法被一个没加事务的接口方法调用,从而整个creatSalaryMonthStatistic方法都没有事务效果:
//此接口方法未加事务
public Boolean batchInitSalaryFileDataTask4Tenant(String tenantId){
.....
salaryFileInitTaskBiz.createSalaryFileDateInitTask4Staff(file);
.....
}
四:解决方案
知道了引起问题的原因,解决方法也比较简单,有好几种方法都可以解决这个问题,可以根据个人需要选择一种解决方法,本文列出其中三种:
1.比较方便、暴力的一种方法就是直接在最外层接口方法中添加事务注解,也就是给本文中的batchInitSalaryFileDataTask4Tenant方法加上注解即可。
2.也可以通过代理类调用creatSalaryMonthStatistic方法,代理类中包含了事务逻辑,这样也能实现事务功能。
3.还可以直接将creatSalaryMonthStatistic这个方法放到另外一个类中。
记一次实际开发过程中遇到事务报错问题 Transaction synchronization is not active的更多相关文章
- MAC OS 中mount nfs 报错问题.
记一下 MAC OS 中mount nfs 报错问题. 环境和配置文件 NFS 服务端 Ubuntu 安装 apt install nfs-kernel-server 服务端的配置文件 cat /et ...
- 解决MyEclipse中的js报错的小方法
今天,下了个模版,但是导进去的时候发现js会报错.看了下其他都没有错误.而有一个js报错误,请原谅我有点红色强迫症,不能留一点红色 . 错误如下:Syntax error on token " ...
- 关于Entity Framework中的Attached报错相关解决方案的总结
关于Entity Framework中的Attached报错的问题,我这里分为以下几种类型,每种类型我都给出相应的解决方案,希望能给大家带来一些的帮助,当然作为读者的您如果觉得有不同的意见或更好的方法 ...
- 关于Entity Framework中的Attached报错的完美解决方案终极版
之前发表过一篇文章题为<关于Entity Framework中的Attached报错的完美解决方案>,那篇文章确实能解决单个实体在进行更新.删除时Attached的报错,注意我这里说的单个 ...
- Eclipse中启动tomcat报错:A child container failed during start
我真的很崩溃,先是workspace崩了,费了好久重建的workspace,然后建立了一个小demo项目,tomcat中启动却报错,挑选其中比较重要的2条信息如下: A child container ...
- MyEclipse8.6中提交SVN报错
上周五(11月27日)的时候,从TortoiseSVN提交项目报错,然后直接从MyEclipse中检出来,修改后提交同样报错. MyEclipse8.6中提交SVN报错,错误提示如下: commit ...
- idea中编译项目报错 java: javacTask: 源版本 1.8 需要目标版本 1.8
问题如上面所叙: > idea中编译项目报错 java: javacTask: 源版本 1.8 需要目标版本 1.8 解决方案: > Setting->Compiler->Ja ...
- .vue文件在webstorm中es6语法报错解决方法
1 语法支持es6设置 Preferences > Languages & Frameworks > JavaScript 把 Javascript Language versio ...
- pycharm 中 import requests 报错
一 , 使用Pycharm来抓取网页的时候,要导入requests模块,但是在pycharm中 import requests 报错. 原因: python中还没有安装requests库 解决办法: ...
随机推荐
- ROS 机器人技术 - 解决 ROS_INFO 不能正确输出 string 的问题!
一.输出「??」 项目调试一个节点,打印 ROS 信息时发现设置的节点名称都是问号: ROS_INFO("[%s]: camera_extrinsic_mat", kNodeNam ...
- Email地址验证
<script>function validateForm(){ var x=document.forms["myForm"]["email"].v ...
- 安装 KubeSphere DevOps 系统
1. 安装KubeSphere 安装了一夜,终于看到了期待已久的画面 第一步.硬件配置(PS:VirtualBox虚拟机): 操作系统:Ubuntu 18.04 CPU:4核 内存:8G 磁盘:60 ...
- java中的引用类型:强软弱虚
java中的引用类型共4种:强软弱虚,具体每种类型的特点和应用场景.记录下.本文是看了马士兵老师的视频后记录整理的.加深印象. 基本概念 1. 强引用 强引用是使用最普遍的引用.如果一个对象具有强引用 ...
- python中的类型
python中的类型分为四种 1.整形 2.浮点型 3.字符串 4.对象(除了前三种,其他的都是对象) 比如函数也是对象 def fun(): print(123) type(fun) // < ...
- 攻防世界misc新手区前三题
1.this_is_flag 从题目以及题目的描述来看,不难发现实际上题目中所描述的就是flag 2.Pdf 拿到题目附件是pdf文件,观察题目描述,题目说图下面什么都没有,那么十有八九图下面肯定是f ...
- 将MySQL库的表转入到MSSQL中的某个库中(Employees下的Employees表 → pubs库下)_2
将MySQL库的表转入到MSSQL中的某个库中(Employees下的Employees表 → pubs库下, 此pubs下的表名是employee,不冲突),方法大致以下几个(另有其他方法待补充), ...
- IP组网实验(使用Cisco Packet Tracer路由器模拟软件)
最近计网课讲到了以太网,第二个计网实验就是IP组网实验.这个实验主要使用了netsim这个路由器模拟软件.怎奈mac上没有,于是用Cisco Packet Tracer进行了一次模拟(其实就是实验中的 ...
- tcpdump抓包工具的基本使用
为了更好的深入理解计算机网络等相关知识,例如TCP\UDP\IP等,我们就必须利用tcpdump.Wireshark等工具对网络进行分析.本篇博文主要记录一下tcpdump这个网络分析利器的一些基本使 ...
- 【JMeter_16】JMeter逻辑控制器__随机控制器<Random Controller>
随机控制器<Random Controller> 业务逻辑: 当每次执行到该逻辑控制器时,随机挑选控制器下的任意一个子节点<取样器.逻辑控制器> Ignore sub-cont ...