一:问题场景

在一次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. ODEINT 求解常微分方程(3)

    import numpy as np from scipy.integrate import odeint import matplotlib.pyplot as plt # function tha ...

  2. Vue —— VueX精讲(1)

    大纲 这一讲我们最主要的就是学习vue中的数据管理VueX,这个是一个大杀器 一.回顾一些Promise相关的东西 Promise 有几个比较重要的方法,最重要的还是有一个叫做all的方法,这个也是非 ...

  3. C#数据结构与算法系列(二):稀疏数组(SparseArray)

    1.介绍 当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组.    稀疏数组的处理方法是: 1.记录数组一共有几行几列,有多少个不同的值    2.把具有不同值的元素的 ...

  4. 跟着视频学python,Day1

    python介绍 发展史 安装 Hello World程序 变量 用户输入 模块初识 数据类型初识 条件表达式if...elif...else 循环表达式while 循环表达式for python介绍 ...

  5. PAI-AutoLearning 图像分类使用教程

    概述 PAI AutoLearning(简称PAI AL)自动学习支持在线标注.自动模型训练.超参优化以及模型评估.在平台上只需准备少量标注数据,设置训练时长即可得到深度优化的模型.同时自动学习PAI ...

  6. 通过数据库客户端界面工具DBeaver连接Hive

    前言 本文讲解如何通过数据库客户端界面工具DBeaver连接hive,并解决驱动下载不下来的问题. 1.为什么使用客户端界面工具 为什么使用客户端界面工具而不用命令行使用hive 通过界面工具查看分析 ...

  7. HTMLTestRunner生成html测试报告

    使用:把文件放到项目某个文件夹中,引入方式如下 import unittest import env import vendor.report.HTMLTestRunnerNew as HTMLTes ...

  8. C#数据结构与算法系列(五):常见单链表笔试

    1.求单链表中有效节点个数 public static int GetLength(HeroNode headNode) { int length = ; var cur = headNode.Nex ...

  9. UltraEdit常用技巧

    Tip 1: Alt+C 列模式可以说最初选择使用这个文本编辑软件,原因很简单,就是因为“她”具有列编辑模式.如果您还不知道什么是列编辑模式的话,我想您应该好好研究一下啦.这是一个超级“赞”的功能.在 ...

  10. php 判断设备是手机还是平板还是pc

    1 <?php 2 //获取USER AGENT 3 $agent = strtolower($_SERVER['HTTP_USER_AGENT']); 4 5 //分析数据 6 $is_pc ...