关于加@Transactional注解的方法之间调用,事务是否生效的问题
时间:2022-07-24
本文章向大家介绍关于加@Transactional注解的方法之间调用,事务是否生效的问题,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
1. 不同类之间的方法调用,如类A的方法a()调用类B的方法b(),这种情况事务是正常起作用的。只要方法a()或b()配置了事务,运行中就会开启事务,产生代理。
若两个方法都配置了事务,两个事务具体以何种方式传播,取决于设置的事务传播特性。
2. 同一个类内方法调用:重点来了,同一个类内的方法调用就没那么简单了,假定类A的方法a()调用方法b()
- 同一类内方法调用,无论被调用的b()方法是否配置了事务,此事务在被调用时都将不生效。
看一个例子:
@Servicepublic class UserServiceImpl implements UserService {
@Autowired private UserDao userDao;
public int insertUser(User user) {
userDao.insertUser(user);
// 调用同类方法
this.selectUser(user.getId());
return 1;
}
@Transactional
public String selectUser(int id) {
throw new RuntimeException();
//return
userDao.selectUser(id);
}
public int updateUser(User user) {
return userDao.updateUser(0, user); }
}
service层中,insertUser()方法没有配置事务,selectUser()配置了事务,在insertUser()中调用selectUser()时,查看日志如下:
[DEBUG][2018-02-22 11:00:32] org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:104) drop table if exists user
Hibernate: drop table if exists user
[DEBUG][2018-02-22 11:00:32] org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:104) create table user (id integer not null auto_increment, createdDate datetime, email varchar(255), name varchar(20) not null, password varchar(255), phone varchar(255), updatedDate datetime, primary key (id))
Hibernate: create table user (id integer not null auto_increment, createdDate datetime, email varchar(255), name varchar(20) not null, password varchar(255), phone varchar(255), updatedDate datetime, primary key (id))
[INFO][2018-02-22 11:00:32] org.hibernate.tool.hbm2ddl.SchemaExport.execute(SchemaExport.java:406) HHH000230: Schema export complete
[DEBUG][2018-02-22 11:00:32] org.hibernate.internal.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:1073) Checking 0 named HQL queries
[DEBUG][2018-02-22 11:00:32] org.hibernate.internal.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:1096) Checking 0 named SQL queries
[DEBUG][2018-02-22 11:00:32] org.hibernate.stat.internal.StatisticsInitiator.initiateServiceInternal(StatisticsInitiator.java:110) Statistics initialized [enabled=false]
[INFO][2018-02-22 11:00:33] org.springframework.orm.hibernate4.HibernateTransactionManager.afterPropertiesSet(HibernateTransactionManager.java:360) Using DataSource [com.mchange.v2.c3p0.ComboPooledDataSource[ identityToken -> 1hge15x9t1g0fr98s704x1|72d1ad2e, dataSourceName -> 1hge15x9t1g0fr98s704x1|72d1ad2e ]] of Hibernate SessionFactory for HibernateTransactionManager
[DEBUG][2018-02-22 11:00:33] org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:228) Executing identity-insert immediately
[DEBUG][2018-02-22 11:00:33] org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:104) insert into user (createdDate, email, name, password, phone, updatedDate) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into user (createdDate, email, name, password, phone, updatedDate) values (?, ?, ?, ?, ?, ?)
[DEBUG][2018-02-22 11:00:33] org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:212) Obtaining JDBC connection
[DEBUG][2018-02-22 11:00:33] org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:218) Obtained JDBC connection
[DEBUG][2018-02-22 11:00:33] org.hibernate.id.IdentifierGeneratorHelper.getGeneratedIdentity(IdentifierGeneratorHelper.java:93) Natively generated identity: 1
[DEBUG][2018-02-22 11:00:33] org.hibernate.hql.internal.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:267) parse() - HQL: select name from com.wcl.pojo.User u where u.id = ?
[DEBUG][2018-02-22 11:00:33] org.hibernate.hql.internal.ast.QueryTranslatorImpl.showHqlAst(QueryTranslatorImpl.java:285) --- HQL AST ---
可见没有开启事务,因此selectUser()的事务配置没有生效,抛异常后也不会回滚。
另一个例子:方法a()配置了事务,此时b()的事务虽然不生效,但a()的事务生效,对于b()中抛出的异常也会回滚。
[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:104) drop table if exists user
Hibernate: drop table if exists user
[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:104) create table user (id integer not null auto_increment, createdDate datetime, email varchar(255), name varchar(20) not null, password varchar(255), phone varchar(255), updatedDate datetime, primary key (id))
Hibernate: create table user (id integer not null auto_increment, createdDate datetime, email varchar(255), name varchar(20) not null, password varchar(255), phone varchar(255), updatedDate datetime, primary key (id))
[INFO][2018-02-22 11:08:50] org.hibernate.tool.hbm2ddl.SchemaExport.execute(SchemaExport.java:406) HHH000230: Schema export complete
[DEBUG][2018-02-22 11:08:50] org.hibernate.internal.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:1073) Checking 0 named HQL queries
[DEBUG][2018-02-22 11:08:50] org.hibernate.internal.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:1096) Checking 0 named SQL queries
[DEBUG][2018-02-22 11:08:50] org.hibernate.stat.internal.StatisticsInitiator.initiateServiceInternal(StatisticsInitiator.java:110) Statistics initialized [enabled=false]
[INFO][2018-02-22 11:08:50] org.springframework.orm.hibernate4.HibernateTransactionManager.afterPropertiesSet(HibernateTransactionManager.java:360) Using DataSource [com.mchange.v2.c3p0.ComboPooledDataSource[ identityToken -> 1hge15x9t1g0qf4c3bcmx8|399f45b1, dataSourceName -> 1hge15x9t1g0qf4c3bcmx8|399f45b1 ]] of Hibernate SessionFactory for HibernateTransactionManager
[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:212) Obtaining JDBC connection
[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.jdbc.inter<a href="http://blog.csdn.net/JIESA/article/details/53438342">nal.LogicalCo</a>nnectionImpl.obtainConnection(LogicalConnectionImpl.java:218) Obtained JDBC connection
<span style="color:#ff0000;">[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:158) begin
[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:69) initial autocommit status: true
[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:71) disabling autocommit </span>
[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:228) Executing identity-insert immediately
[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:104) insert into user (createdDate, email, name, password, phone, updatedDate) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into user (createdDate, email, name, password, phone, updatedDate) values (?, ?, ?, ?, ?, ?)
[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:212) Obtaining JDBC connection
[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:218) Obtained JDBC connection
[DEBUG][2018-02-22 11:08:50] org.hibernate.id.IdentifierGeneratorHelper.getGeneratedIdentity(IdentifierGeneratorHelper.java:93) Natively generated identity: 1
<span style="color:#ff0000;">[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.transaction.spi.AbstractTransactionImpl.rollback(AbstractTransactionImpl.java:203) rolling back
[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doRollback(JdbcTransaction.java:164) rolled JDBC Connection </span>
[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.releaseManagedConnection(JdbcTransaction.java:126) re-enabling autocommit
[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.releaseConnection(LogicalConnectionImpl.java:232) Releasing JDBC connection
[DEBUG][2018-02-22 11:08:50] org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.releaseConnection(LogicalConnectionImpl.java:250) Released JDBC connection
Exception in thread "main" java.lang.RuntimeException
at com.wcl.service.UserServiceImpl.selectUser(UserServiceImpl.java:26)
at com.wcl.service.UserServiceImpl.insertUser(UserServiceImpl.java:20)
3. 不生效的原因?
有几篇文章探究了事务这个特性的原因,spring声明式事务 同一类内方法调用事务失效
个人理解,当从类外调用方法a()时,从spring容器获取到的serviceImpl对象实际是包装好的proxy对象,因此调用a()方法的对象是动态代理对象。而在类内部a()调用b()的过程中,实质执行的代码是this.b(),此处this对象是实际的serviceImpl对象而不是本该生成的代理对象,因此直接调用了b()方法。
aop原理跟事务一样,往大里说是动态代理,往小里说是反射机制。我又测试了两个方法,分别加上aop增强通知,类内调用的效果跟事务是一样的。这里最好研究一下spring aop和事务的源码,应该能搞得更清楚。
- 循序渐进调优union相关的sql(r2笔记23天)
- 对分区表导入导出的水平,垂直切分(r2第22天)
- 巧用parallel极速提升数据加载速度(r2第21天)
- 【Windows编程】创建多文档界面
- 生产环境sqlldr加载性能问题及分析之二(r2第20天)
- [Python]从豆瓣批量获取看过电影的用户列表,并应用kNN算法预测用户性别
- 关于desc的一个奇怪问题及分析(r2第18天)
- R语言进行中文分词,并对6W条微博聚类
- 只言片语分析datapump的工作原理(r2第18天)
- 开发 | TensorFlow全新的数据读取方式:Dataset API入门教程
- 用python实现支持向量机对婚介数据的用户配对预测
- SQL*Loader-805的解决(r2笔记36天)
- 用python实现决策树ID3算法,对隐形眼镜类型预测
- 用GA算法设计22个地点之间最短旅程-R语言实现
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【从0到1学算法】二分查找法
- Spring事务源码分析专题(二)Mybatis的使用及跟Spring整合原理分析
- IIC
- JVM系列之:Contend注解和false-sharing
- FFmpeg 实现视频 封装 与 解封装
- 万物皆可状态机
- ggplot2折线图展示美国和印度COVID-19单日新增确诊人数变化趋势
- JBrowse安装配置的一些教程
- 对不起,网上找的Redis分布式锁都有漏洞!
- 打卡群刷题总结0722——颜色分类
- 为什么Python没有main函数?
- 构建对象检测模型
- OpenCV4.4 + YOLOv4 真的可以运行了…..
- 基于分类任务的信号(EEG)处理
- 面试:如何决定使用 HashMap 还是 TreeMap?