Spring,为内部方法新起一个事务,此处应有坑。
事务的作用,使我们操作能够连贯起来。而spring则是提供了一个更简单的方法,只要使用 @Transactional 一个注解,就可以保证操作的连贯性了。
普通用法,稍后再说,这里要说的是: 在最外面的方法中,有一个@Transactional 的注解,当有抛出异常时,则进行回滚操作:
@Transactional(readOnly = false, rollbackFor = Throwable.class, isolation = Isolation.REPEATABLE_READ)
原本这个方法运行得好好的,但是有一天,我们需要在这个方法里添加一个新业务操作,而且这个业务操作是不要求回滚的,类似于做日志记录一类的。WHAT SHOULD I DO ?
由于业务的独特性,我能够快速想到的是,在这个类里面加一个private方法,然后直接去调用就ok了,如果说还是考虑到回滚的话,我也快速想到 @Transactional 的NOT_SUPPORTED传播特性,如:
@Transactional(propagation = Propagation.NOT_SUPPORTED)
private void doMyExJob(UserDebitCardBean userDebitCard) {
System.out.println("do my job...");
//do my job...
}
这看起来很合理,没毛病。
然而就是运行不起来,只要外面调用的方法一抛出异常,那么这个新方法的数据操作将会被回滚。妈蛋,到底哪里出了问题???仔细查了下资料,原来 @Transactional 注解由于原理决定了他只能作用于public方法中,而这里改为private,就完全被忽略无视了。OK,改呗:
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void doMyExJob(UserDebitCardBean userDebitCard) {
System.out.println("do my job...");
//do my job...
}
感觉应该好了,然而并没有。我也是醉了,这个问题,如果仔细花时间,找原理是没有问题的,但是在关键时刻来这么一下,还是很不爽的。 网上看到一哥们说,还必须要将方法写到另一个类中,而且要通过spring的注入方式进行调用,才可以。好吧,那我就按照他的来,结果真的成功了。
//在接口中进行了定义,能够注入
@Override
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void doMyExJob(UserDebitCardBean userDebitCard) {
System.out.println("do my job...");
//do my job...
}
总算可以了,在赶时间的时候,能够解决问题的,就是好方法。至此,问题解决。1. 使用public访求;2. 写在外部类中,可被调用; 3. 使用注入的方式进行该方法的执行。
说实话,spring这种事务还是有点不太好用的,要求太多,当然了,有很大部分原因是我没有理解其精髓。OK,下面我们来看看spring事务的讲解:
在配置文件中,默认情况下,<tx:annotation-driven>会自动使用名称为transactionManager的事务管理器。所以,如果定义的事务管理器名称为transactionManager,那么就可以直接使用<tx:annotation-driven/>。如下:
|
1
2
3
4
5
6
7
8
|
<!-- 配置事务管理器 --><beanid="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"></bean><!-- enables scanning for @Transactional annotations --><tx:annotation-driven/> |
<tx:annotation-driven>一共有四个属性如下,
- mode:指定Spring事务管理框架创建通知bean的方式。可用的值有proxy和aspectj。前者是默认值,表示通知对象是个JDK代理;后者表示Spring AOP会使用AspectJ创建代理
- proxy-target-class:如果为true,Spring将创建子类来代理业务类;如果为false,则使用基于接口的代理。(如果使用子类代理,需要在类路径中添加CGLib.jar类库)
- order:如果业务类除事务切面外,还需要织入其他的切面,通过该属性可以控制事务切面在目标连接点的织入顺序。
- transaction-manager:指定到现有的PlatformTransaction Manager bean的引用,通知会使用该引用
@Transactional的属性
isolation 枚举org.springframework.transaction.annotation.Isolation的值 事务隔离级别
noRollbackFor Class<? extends Throwable>[] 一组异常类,遇到时不回滚。默认为{}
noRollbackForClassName Stirng[] 一组异常类名,遇到时不回滚,默认为{}
propagation 枚举org.springframework.transaction.annotation.Propagation的值 事务传播行为
readOnly boolean 事务读写性
rollbackFor Class<? extends Throwable>[] 一组异常类,遇到时回滚
rollbackForClassName Stirng[] 一组异常类名,遇到时回滚
timeout int 超时时间,以秒为单位
value String 可选的限定描述符,指定使用的事务管理器
@Transactional标注的位置
@Transactional注解可以标注在类和方法上,也可以标注在定义的接口和接口方法上。
如果我们在接口上标注@Transactional注解,会留下这样的隐患:因为注解不能被继承,所以业务接口中标注的@Transactional注解不会被业务实现类继承。所以可能会出现不启动事务的情况。所以,spring建议我们将@Transaction注解在实现类上。
在方法上的@Transactional注解会覆盖掉类上的@Transactional。
注意:
@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。
虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。
默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。
拼的就是工具的使用熟练度,哦。
Spring,为内部方法新起一个事务,此处应有坑。的更多相关文章
- SpringBoot 内部方法调用,事务不起作用的原因及解决办法
在做业务开发时,遇到了一个事务不起作用的问题.大概流程是这样的,方法内部的定时任务调用了一个带事务的方法,失败后事务没有回滚.查阅资料后,问题得到解决,记录下来分享给大家. 场景 我在这里模拟一个场景 ...
- Spring单实例、多线程安全、事务解析
原文:http://blog.csdn.net/c289054531/article/details/9196053 引言: 在使用Spring时,很多人可能对Spring中为什么DAO和Se ...
- Springmvc+Spring+Hibernate搭建方法
Springmvc+Spring+Hibernate搭建方法及example 前面两篇文章,分别介绍了Springmvc和Spring的搭建方法,本文再搭建hibernate,并建立SSH最基本的代码 ...
- spring框架学习(六)AOP事务及spring管理事务方式之Template模板
概念 1.事务 1)事务特性:ACID 原子性 :强调事务的不可分割. 一致性 :事务的执行的前后数据的完整性保持一致. 隔离性 :一个事务执行的过程中,不应该受到其他事务的干扰. 持久性 :事务一旦 ...
- Spring service本类中方法调用另一个方法事务不生效问题(转载)
前些日子一朋友在需要在目标对象中进行自我调用,且需要实施相应的事务定义,且网上的一种通过BeanPostProcessor的解决方案是存在问题的.因此专门写此篇帖子分析why. 1.预备知识 aop概 ...
- spring 默认情况下事务是惟一的 同一个方法里面第一个sql开启后 在执行完 将事务传递给下一个sql
spring 默认情况下事务是惟一的 同一个方法里面第一个sql开启后 在执行完 将事务传递给下一个sql
- 使用spring声明式事务,spring使用AOP来支持声明式事务,会根据事务属性,自动在方法调用之前决定是否开启一个事务,并在方法执行之后决定事务提交或回滚事务。
使用spring声明式事务,spring使用AOP来支持声明式事务,会根据事务属性,自动在方法调用之前决定是否开启一个事务,并在方法执行之后决定事务提交或回滚事务.
- [spring transaction],service实现类中非事务方法直接调用自身事务方法导致事务无效的原因
首先,准备service接口,两个 public interface AccountService { public void createAccount(Account account, int t ...
- 一个事务复制的bug--更新丢失
有两种情况会造成更新丢失,第一种是不正确的设置,例如外键或触发器的“Not For Replication” (NFR)属性没有开启.详情请参考http://blogs.msdn.com/b/apgc ...
随机推荐
- Android Studio模拟器磁盘空间不足(Not enough disk space to run AVD)
在Android Studio中运行模拟器时,提示Error: Not enough disk space to run AVD '....'. Exiting.是说安装模拟的磁盘空间不足,导致无法运 ...
- 如何将R中的data frame对象的数据导入到DB
在使用ARIMA模型来预测我们的销量的时候,如果保存预测版本进DB,以供后续分析呢 1. 在定义变量阶段我们定义了dfResult <- data.frame() 这是一个data f ...
- html阿里云网页练习实现代码
html <body> <!-- 固定浮动栏 --> <div class="guding"> <p> ...
- mysql修改密码方法
1. 修改密码有三种方法:1.1 ---->用mysqladmin修改密码格式:mysqladmin -u用户名 -p旧密码 password 新密码 例子:# mysqladmin -uroo ...
- sonar gitlab+jenkins配置
sonar.projectKey=test-news-activitysonar.projectName=test-news-activitysonar.projectVersion=$BUILD_N ...
- python note 02 格式化与判断、字符串转换
1.格式化输出% %s %d name = input ('请输入姓名:') age = input ('请输入年龄:') height = input ('请输入身高:') msg = " ...
- 365. Water and Jug Problem量杯灌水问题
[抄题]: 简而言之:只能对 杯子中全部的水/容量-杯子中全部的水进行操作 You are given two jugs with capacities x and y litres. There i ...
- [leetcode]364. Nested List Weight Sum II嵌套列表加权和II
Given a nested list of integers, return the sum of all integers in the list weighted by their depth. ...
- Sublime Text3快捷键大全
选择类 Ctrl+D 选中光标所占的文本,继续操作则会选中下一个相同的文本. Alt+F3 选中文本按下快捷键,即可一次性选择全部的相同文本进行同时编辑.举个栗子:快速选中并更改所有相同的变量名.函数 ...
- IMU
(1)用IMU来进行预测 读入一个10/20帧的数据集,通过IMU来初步预测出位姿以及显示其路径. Christian Forster, Luca Carlone, Frank Dellaert, D ...