一:问题场景

在一次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的更多相关文章

  1. MAC OS 中mount nfs 报错问题.

    记一下 MAC OS 中mount nfs 报错问题. 环境和配置文件 NFS 服务端 Ubuntu 安装 apt install nfs-kernel-server 服务端的配置文件 cat /et ...

  2. 解决MyEclipse中的js报错的小方法

    今天,下了个模版,但是导进去的时候发现js会报错.看了下其他都没有错误.而有一个js报错误,请原谅我有点红色强迫症,不能留一点红色 . 错误如下:Syntax error on token " ...

  3. 关于Entity Framework中的Attached报错相关解决方案的总结

    关于Entity Framework中的Attached报错的问题,我这里分为以下几种类型,每种类型我都给出相应的解决方案,希望能给大家带来一些的帮助,当然作为读者的您如果觉得有不同的意见或更好的方法 ...

  4. 关于Entity Framework中的Attached报错的完美解决方案终极版

    之前发表过一篇文章题为<关于Entity Framework中的Attached报错的完美解决方案>,那篇文章确实能解决单个实体在进行更新.删除时Attached的报错,注意我这里说的单个 ...

  5. Eclipse中启动tomcat报错:A child container failed during start

    我真的很崩溃,先是workspace崩了,费了好久重建的workspace,然后建立了一个小demo项目,tomcat中启动却报错,挑选其中比较重要的2条信息如下: A child container ...

  6. MyEclipse8.6中提交SVN报错

    上周五(11月27日)的时候,从TortoiseSVN提交项目报错,然后直接从MyEclipse中检出来,修改后提交同样报错. MyEclipse8.6中提交SVN报错,错误提示如下: commit ...

  7. idea中编译项目报错 java: javacTask: 源版本 1.8 需要目标版本 1.8

    问题如上面所叙: > idea中编译项目报错 java: javacTask: 源版本 1.8 需要目标版本 1.8 解决方案: > Setting->Compiler->Ja ...

  8. .vue文件在webstorm中es6语法报错解决方法

    1 语法支持es6设置 Preferences > Languages & Frameworks > JavaScript 把 Javascript Language versio ...

  9. pycharm 中 import requests 报错

    一 , 使用Pycharm来抓取网页的时候,要导入requests模块,但是在pycharm中 import requests 报错. 原因: python中还没有安装requests库 解决办法: ...

随机推荐

  1. python IDE pycharm的安装与使用

    Python开发最牛逼的IDE——pycharm (其实其它的工具,例如eclipse也可以写,只不过比较麻烦,需要安装很多的插件,所以说pycharm是最牛逼的) pycharm,下载专业版的,不要 ...

  2. iOS-Code Data的快速体验

    Code Data Core Data 是iOS SDK 里的一个很强大的框架,允许程序员以面向对象的方式储存和管理数据.使用Core Data框架,程序员可以很轻松有效地通过面向对象的接口管理数据 ...

  3. KMP 知识点整理

    1.扩展KMP 2.最大表示法 3.最小表示法 (扩展KMP) hdu2594  模板题 #include <iostream> #include <cstdio> #incl ...

  4. 4.vue class 绑定- model基础应用

        //代码可以复制自行体验   <template>     <div id="app" @click.stop="test('你点击了我big- ...

  5. java中的引用类型:强软弱虚

    java中的引用类型共4种:强软弱虚,具体每种类型的特点和应用场景.记录下.本文是看了马士兵老师的视频后记录整理的.加深印象. 基本概念 1. 强引用 强引用是使用最普遍的引用.如果一个对象具有强引用 ...

  6. MongoDB 基础知识学习笔记

    注意:本文假设您已经安装好 MongoDB 数据库并启动它了. 连接 MongoDB.数据库操作.集合操作 连接 MongoDB mongo ip:port/dbName -u username -p ...

  7. foreach 集合又抛经典异常了,这次一定要刨根问底

    一:背景 1. 讲故事 最近同事在写一段业务逻辑的时候,程序跑起来总是报:集合已修改:可能无法执行枚举操作,硬是没有找到什么情况下会导致这个异常产生,就让我来找一下bug,其实这个异常在座的每个程序员 ...

  8. Quartz.Net系列(二):介绍、简单使用、对比Windows计划任务

    1.介绍 Quartz是功能强大的开源作业调度库,几乎可以集成到任何Java应用程序中-从最小的独立应用程序到最大的电子商务系统.Quartz可用于创建简单或复杂的计划,以执行数以万计,数以万计的工作 ...

  9. 从零开始的Spring Boot(2、在Spring Boot中整合Servlet、Filter、Listener的方式)

    在Spring Boot中整合Servlet.Filter.Listener的方式 写在前面 从零开始的Spring Boot(1.搭建一个Spring Boot项目Hello World):http ...

  10. (十)深入理解maven构建生命周期和各种plugin插件

    链接:https://blog.csdn.net/zhaojianting/article/details/80321488