记一次实际开发过程中遇到事务报错问题 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库 解决办法: ...
随机推荐
- 🧑🏻💻数据库简介及Mac平台环境搭建🧑🏻💻
数据库 存储数据的演变过程 如果没有使用数据库,我们自己存放文件,数据格式是千差万别的,完全取决于我们自己,例如: """ # 张三 zhangsan|123|read ...
- C语言视频教程下载(百万年薪程序员录制,免费公开)
<C/C++语言高性能服务开发基础>您可以自由下载.传播.发布或其它商业用途. 视频文件共13.6G,提供了QQ群文件和百度网盘两种方法,建议采用QQ群文件下载,速度较快. 一.下载方法 ...
- group by <grouping sets(...) ><cube(...)>
GROUP BY GROUPING SETS() 后面将还会写学习 with cube, with rollup,以及将它们转换为标准的GROUP BY的子句GROUP SET(), CU ...
- 全网最完整的Redis入门指导
前言 本文提供全网最完整的Redis入门指导教程,下面我们从下载Redis安装包开始,一步一步的学习使用. 下载Redis 官网提供的Redis安装包是服务于Linux的,而我们需要在Window下使 ...
- pip速度过慢解决方法
国内源: 新版ubuntu要求使用https源,要注意. 清华:https://pypi.tuna.tsinghua.edu.cn/simple 阿里云:http://mirrors.aliyun.c ...
- Windows 程序设计(4) MFC-02 基本控件-上
1. Button 按钮控件 1.1.按钮控件的基本使用 新建对话框工程,拖拽按钮控件,添加点击事件响应函数! a.双击模版进行添加: b.事件方式进行添加: button的常见事件类型 void C ...
- Laya 吐槽日志.
新换了一个公司,公司有两个产品都是用的laya, 一个as写的2D游戏, 一个ts写的3D游戏 as写小游戏,各种不舒服啊, 一堆 __JS这样的代码, 体验极差. laya IDE 按钮只能做 ...
- 无法解析的外部符号 "public: virtual struct CRuntimeClass * _
SetupPropertyPage.obj : error LNK2001: 无法解析的外部符号 "public: virtual struct CRuntimeClass * __this ...
- 001.OpenShift介绍
一 OpenShift特性 1.1 OpenShift概述 Red Hat OpenShijft Container Platform (OpenShift)是一个容器应用程序平台,它为开发人员和IT ...
- Machine Learning Note
[Andrew Ng NIPS2016演讲]<Nuts and Bolts of Applying Deep Learning (Andrew Ng) 中文详解:https://mp.weixi ...