- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章解决@Transaction注解导致动态切换更改数据库失效问题由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
当给Controller方法加上@Transaction注解后,动态切换数据源就失效了,原因是每次@Before注解的方法运行之前,protected abstract Object determineCurrentLookupKey();就已经运行了,而这个方法是切换数据源的关键.
其实也算不上解决,就是不要在Controller方法上加事务注解,非要加事务,中间的Service层就不要省了.
为非public方法,这个时候@Transactional会实现.
失败的原理是:@Transactional是基于动态代理来实现的,非public的方法,他@Transactional的动态代理对象信息为空,所以不能回滚.
调用了@Transactional方法时,当你调用是,他也不会回滚 。
测试代码如下 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@Service
public
class
UserServiceImpl
extends
BaseServiceImpl<UserEntity>
implements
UserService {
@Autowired
private
UserMapper userMapper;
@Override
@Transactional
public
void
insertOne() {
UserEntity userEntity =
new
UserEntity();
userEntity.setUsername(
"Michael_C_2019"
);
//插入到数据库
userMapper.insertSelective(userEntity);
//手动抛出异常
throw
new
IndexOutOfBoundsException();
}
@Override
public
void
saveOne() {
insertOne();
}
}
|
失败的原理:@Transactional是基于动态代理对象来实现的,而在类内部的方法的调用是通过this关键字来实现的,没有经过动态代理对象,所以事务回滚失效.
没有在catch代码块里面重新抛出异常,事务也不会回滚.
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@Override
@Transactional
public
void
insertOne() {
try
{
UserEntity userEntity =
new
UserEntity();
userEntity.setUsername(
"Michael_C_2019"
);
//插入到数据库
userMapper.insertSelective(userEntity);
//手动抛出异常
throw
new
IndexOutOfBoundsException();
}
catch
(IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
|
所以在阿里巴巴的Java开发者手册里面有明确规定,在 @Transactional的方法里面捕获了异常,必须要手动回滚, 。
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@Override
@Transactional
public
void
insertOne() {
try
{
UserEntity userEntity =
new
UserEntity();
userEntity.setUsername(
"Michael_C_2019"
);
//插入到数据库
userMapper.insertSelective(userEntity);
//手动抛出异常
throw
new
IndexOutOfBoundsException();
}
catch
(IndexOutOfBoundsException e) {
e.printStackTrace();
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
|
失败原理:这时候我们来看看spring的源码:
TransactionAspectSupport类里面的invokeWithinTransaction方法 。
1
|
TransactionAspectSupport
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
@Nullable
protected
Object invokeWithinTransaction(Method method,
@Nullable
Class<?> targetClass, TransactionAspectSupport.InvocationCallback invocation)
throws
Throwable {
TransactionAttributeSource tas =
this
.getTransactionAttributeSource();
TransactionAttribute txAttr = tas !=
null
? tas.getTransactionAttribute(method, targetClass) :
null
;
PlatformTransactionManager tm =
this
.determineTransactionManager(txAttr);
String joinpointIdentification =
this
.methodIdentification(method, targetClass, txAttr);
Object result;
if
(txAttr !=
null
&& tm
instanceof
CallbackPreferringPlatformTransactionManager) {
TransactionAspectSupport.ThrowableHolder throwableHolder =
new
TransactionAspectSupport.ThrowableHolder(
null
);
try
{
result = ((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr, (status) -> {
TransactionAspectSupport.TransactionInfo txInfo =
this
.prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
Object var9;
try
{
Object var8 = invocation.proceedWithInvocation();
return
var8;
}
catch
(Throwable var13) {
if
(txAttr.rollbackOn(var13)) {
if
(var13
instanceof
RuntimeException) {
throw
(RuntimeException)var13;
}
throw
new
TransactionAspectSupport.ThrowableHolderException(var13);
}
throwableHolder.throwable = var13;
var9 =
null
;
}
finally
{
this
.cleanupTransactionInfo(txInfo);
}
return
var9;
});
if
(throwableHolder.throwable !=
null
) {
throw
throwableHolder.throwable;
}
else
{
return
result;
}
}
catch
(TransactionAspectSupport.ThrowableHolderException var19) {
throw
var19.getCause();
}
catch
(TransactionSystemException var20) {
if
(throwableHolder.throwable !=
null
) {
this
.logger.error(
"Application exception overridden by commit exception"
, throwableHolder.throwable);
var20.initApplicationException(throwableHolder.throwable);
}
throw
var20;
}
catch
(Throwable var21) {
if
(throwableHolder.throwable !=
null
) {
this
.logger.error(
"Application exception overridden by commit exception"
, throwableHolder.throwable);
}
throw
var21;
}
}
else
{
TransactionAspectSupport.TransactionInfo txInfo =
this
.createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
result =
null
;
try
{
result = invocation.proceedWithInvocation();
}
catch
(Throwable var17) {
//异常时,在catch逻辑中回滚事务
this
.completeTransactionAfterThrowing(txInfo, var17);
throw
var17;
}
finally
{
this
.cleanupTransactionInfo(txInfo);
}
this
.commitTransactionAfterReturning(txInfo);
return
result;
}
}
|
他是通过捕获异常然后在catch里面进行事务的回滚的,所以如果你在自己的方法里面catch了异常,catch里面没有抛出新的异常,那么事务将不会回滚.
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我.
原文链接:https://blog.csdn.net/m0_37659871/article/details/81672373 。
最后此篇关于解决@Transaction注解导致动态切换更改数据库失效问题的文章就讲到这里了,如果你想了解更多关于解决@Transaction注解导致动态切换更改数据库失效问题的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
SO亲爱的 friend 们: 2014 年 3 月 18 日。我正在处理一种情况,在使用 ng-repeat 时,数组内的元素(我从 Json 字符串中获取)更改了原始顺序。 需要明确的是,数组中的
有很多问题询问如何在 JavaScript 单击处理程序中更改 div 的类,例如,此处:Change Div style onclick .我理解得很好(只需更改 .className),并且它有效
我从access导入了一个数据库到mysql,但其中一个表的列名“股数”带有空格,但我尝试更改、替换甚至删除列名,但失败了。任何人都可以帮助解决这一问题 String UpdateQuary = "U
我正在做一个随机的学校元素。 目前,我有一个包含两个 CSS 的页面。一种用于正常 View ,一种用于残障人士 View 。 此页面还包括两个按钮,它们将更改使用的样式表。 function c
我需要使用 javascript 更改 HTML 元素中的文本,但我不知道该怎么做。 ¿有什么帮助吗? 我把它定义成这样: Text I want to change. 我正在尝试这样做: docum
我在它自己的文件 nav_bar.shtml 中有一个主导航栏,每个其他页面都包含该导航栏。这个菜单栏是一个 jQuery 菜单栏(ApyCom 是销售这些导航栏的公司的名称)。导航栏上的元素如何确定
我正在摆弄我的代码,并开始想知道这个变化是否来自: if(array[index] == 0) 对此: if(!array[index] != 0) 可能会影响任何代码,或者它只是做同样的事情而我不需
我一直在想办法调整控制台窗口的大小。这是我正在使用的函数的代码: #include #include #define WIDTH 70 #define HEIGHT 35 HANDLE wHnd;
我有很多情况会导致相同的消息框警报。 有没有比做几个 if 语句更简单/更好的解决方案? PRODUCTS BOX1 BOX2 BOX3
我有一个包含这些元素的 XELEMENT B Bob Petier 19310227 1 我想像这样转换前缀。 B Bob Pet
我使用 MySQL 5.6 遇到了这种情况: 此查询有效并返回预期结果: select * from some_table where a = 'b' and metadata->>"$.countr
我想知道是否有人知道可以检测 R 中日期列格式的任何中断的包或函数,即检测日期向量格式更改的位置,例如: 11/2/90 12/2/90 . . . 15/Feb/1990 16/Feb/1990 .
我希望能够在小部件显示后更改 GtkButton 的标签 char *ButtonStance == "Connect"; GtkWidget *EntryButton = gtk_button_ne
我正在使用 Altera DE2 FPGA 开发板并尝试使用 SD 卡端口和音频线路输出。我正在使用 VHDL 和 C 进行编程,但由于缺乏经验/知识,我在 C 部分遇到了困难。 目前,我可以从 SD
注意到这个链接后: http://www.newscientist.com/blogs/nstv/2010/12/best-videos-of-2010-progress-bar-illusion.h
我想知道在某些情况下,即使剧本任务已成功执行并且 ok=2,ansible 也会显示“changed=0”。使用 Rest API 和 uri 模块时会发生这种情况。我试图找到解释但没有成功。谁能告诉
这个问题已经有答案了: 已关闭12 年前。 Possible Duplicate: add buttons to push notification alert 是否可以在远程通知显示的警报框中指定有
当您的 TabBarController 中有超过 5 个 View Controller 时,系统会自动为您设置一个“更多” View 。是否可以更改此 View 中导航栏的颜色以匹配我正在使用的颜
如何更改.AndroidStudioBeta文件夹的位置,默认情况下,该文件夹位于Windows中的\ .. \ User \ .AndroidStudioBeta,而不会破坏任何内容? /编辑: 找
我目前正在尝试将更具功能性的编程风格应用于涉及低级(基于 LWJGL)GUI 开发的项目。显然,在这种情况下,需要携带很多状态,这在当前版本中是可变的。我的目标是最终拥有一个完全不可变的状态,以避免状
我是一名优秀的程序员,十分优秀!