service层业务代码
@Override
public void test(){
QueryWrapper<StoreRebateCalculateLog> queryWrapper;
queryWrapper = new QueryWrapper<>();
queryWrapper.eq("delete_flag", 0);
//执行查询A,A事务开启
List<StoreRebateCalculateLog> storeRebateCalculateLogs = storeRebateCalculateLogDao.selectBatchIds(Arrays.asList(90010, 90011, 90012, 90013));
//更新,开启B事务
((StoreRebateCalculateLogServiceImpl) AopContext.currentProxy()).updateTest(storeRebateCalculateLogs);//取当前类的代理对象执行,保证在同一个类中的@Transactional注解能够生效
}
@Transactional(rollbackFor = Exception.class)
public void updateTest(List<StoreRebateCalculateLog> storeRebateCalculateLogs1) {
for (StoreRebateCalculateLog log: storeRebateCalculateLogs1) {
log.setNeedRepeatCalFlag("0");
this.storeRebateCalculateLogDao.updateById(log);
}
}
这里先执行一个查询,然后更新操作。查询的方法是一个事务A,后面执行更新操作的方法updateTest因为采用了声明式事务,会重新开启事务,这里记为是事务B。
查看调试模式下的MyBatis执行日志
//创建sqlSession A
Creating a new SqlSession
//为A注册事务
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8d867b]
JDBC Connection [HikariProxyConnection@8519751 wrapping com.mysql.cj.jdbc.ConnectionImpl@2c5cdd] will be managed by Spring
==> Preparing: SELECT calculate_log_id,month_str,day_str,total_count,min_id,max_id,status,need_repeat_cal_flag,delete_flag,creation_date,created_by,version_num,last_update_date,last_updated_by,last_update_login FROM store_rebate_calculate_log WHERE calculate_log_id IN ( ? , ? , ? , ? ) AND delete_flag=0
==> Parameters: 90010(Integer), 90011(Integer), 90012(Integer), 90013(Integer)
<== Columns: calculate_log_id, month_str, day_str, total_count, min_id, max_id, status, need_repeat_cal_flag, delete_flag, creation_date, created_by, version_num, last_update_date, last_updated_by, last_update_login
<== Row: 90010, 2024-03, 20240308, 0, null, null, 2, 1, 0, 2024-03-14 22:20:09, 62169, 9, 2024-03-17 08:40:44, 62169, 62169
<== Row: 90011, 2024-03, 20240309, 0, null, null, 2, 1, 0, 2024-03-14 22:20:09, 62169, 9, 2024-03-17 08:41:45, 62169, 62169
<== Row: 90012, 2024-03, 20240310, 0, null, null, 2, 1, 0, 2024-03-14 22:20:09, 62169, 9, 2024-03-17 08:41:45, 62169, 62169
<== Row: 90013, 2024-03, 20240311, 0, null, null, 2, 1, 0, 2024-03-14 22:20:10, 62169, 2, 2024-03-14 23:34:23, 62169, 62169
<== Total: 4
//释放sqlSession A
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8d867b]
//挂起sqlSession A
Transaction synchronization suspending SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8d867b]
//创建sqlSession B
Creating a new SqlSession
//为B注册事务
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10c1754]
JDBC Connection [HikariProxyConnection@25084448 wrapping com.mysql.cj.jdbc.ConnectionImpl@1e088a3] will be managed by Spring
==> Preparing: UPDATE store_rebate_calculate_log SET month_str=?, day_str=?, total_count=?, status=?, need_repeat_cal_flag=?, creation_date=?, created_by=?, version_num=?, last_update_date=?, last_updated_by=?, last_update_login=? WHERE calculate_log_id=? AND version_num=? AND delete_flag=0
==> Parameters: 2024-03(String), 20240308(String), 0(Integer), 2(String), 0(String), 2024-03-14 22:20:09.0(Timestamp), 62169(Integer), 10(Integer), 2024-03-17 09:56:44.399(Timestamp), 62169(Integer), 62169(Integer), 90010(Long), 9(Integer)
<== Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10c1754]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10c1754] from current transaction
==> Preparing: UPDATE store_rebate_calculate_log SET month_str=?, day_str=?, total_count=?, status=?, need_repeat_cal_flag=?, creation_date=?, created_by=?, version_num=?, last_update_date=?, last_updated_by=?, last_update_login=? WHERE calculate_log_id=? AND version_num=? AND delete_flag=0
==> Parameters: 2024-03(String), 20240309(String), 0(Integer), 2(String), 0(String), 2024-03-14 22:20:09.0(Timestamp), 62169(Integer), 10(Integer), 2024-03-17 09:56:44.415(Timestamp), 62169(Integer), 62169(Integer), 90011(Long), 9(Integer)
<== Updates: 1
//这里省略了一部分更新操作的日志....
//释放sqlSession B
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10c1754]
//提交sqlSession B
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10c1754]
//注销sqlSession B
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10c1754]
//关闭sqlSession B
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10c1754]
//恢复sqlSession A
Transaction synchronization resuming SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8d867b]
//注销sqlSession A
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8d867b]
//关闭sqlSession A
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8d867b]
可以得出下面的流程图
另外需要注意的是,如果上面的
test()
方法也加上@Transactional
注解,结果会是一样吗?
即如下的代码:
@Override
@Transactional(rollbackFor = Exception.class) //这里的区别
public void test(){
QueryWrapper<StoreRebateCalculateLog> queryWrapper;
queryWrapper = new QueryWrapper<>();
queryWrapper.eq("delete_flag", 0);
//执行查询A,A事务开启
List<StoreRebateCalculateLog> storeRebateCalculateLogs = storeRebateCalculateLogDao.selectBatchIds(Arrays.asList(90010, 90011, 90012, 90013));
//更新
((StoreRebateCalculateLogServiceImpl) AopContext.currentProxy()).updateTest(storeRebateCalculateLogs);//取当前类的代理对象执行,保证在同一个类中的@Transactional注解能够生效
}
@Transactional(rollbackFor = Exception.class)
public void updateTest(List<StoreRebateCalculateLog> storeRebateCalculateLogs1) {
for (StoreRebateCalculateLog log: storeRebateCalculateLogs1) {
log.setNeedRepeatCalFlag("0");
this.storeRebateCalculateLogDao.updateById(log);
}
}
跟踪日志发现:
//这里只截取中间部分有差异的日志
==> Preparing: SELECT calculate_log_id,month_str,day_str,total_count,min_id,max_id,status,need_repeat_cal_flag,delete_flag,creation_date,created_by,version_num,last_update_date,last_updated_by,last_update_login FROM store_rebate_calculate_log WHERE calculate_log_id IN ( ? , ? , ? , ? ) AND delete_flag=0
==> Parameters: 90010(Integer), 90011(Integer), 90012(Integer), 90013(Integer)
<== Columns: calculate_log_id, month_str, day_str, total_count, min_id, max_id, status, need_repeat_cal_flag, delete_flag, creation_date, created_by, version_num, last_update_date, last_updated_by, last_update_login
<== Row: 90010, 2024-03, 20240308, 0, null, null, 2, 1, 0, 2024-03-14 22:20:09, 62169, 11, 2024-03-17 10:46:48, 62169, 62169
<== Row: 90011, 2024-03, 20240309, 0, null, null, 2, 1, 0, 2024-03-14 22:20:09, 62169, 11, 2024-03-17 10:47:55, 62169, 62169
<== Row: 90012, 2024-03, 20240310, 0, null, null, 2, 1, 0, 2024-03-14 22:20:09, 62169, 11, 2024-03-17 10:48:03, 62169, 62169
<== Row: 90013, 2024-03, 20240311, 0, null, null, 2, 1, 0, 2024-03-14 22:20:10, 62169, 4, 2024-03-17 10:48:03, 62169, 62169
<== Total: 4
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1f057a7]
//发现这里更新时是从当前的会话中取的sqlSession,用的是同一个sqlSession,没有创建新的sqlSession
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1f057a7] from current transaction
==> Preparing: UPDATE store_rebate_calculate_log SET month_str=?, day_str=?, total_count=?, status=?, need_repeat_cal_flag=?, creation_date=?, created_by=?, version_num=?, last_update_date=?, last_updated_by=?, last_update_login=? WHERE calculate_log_id=? AND version_num=? AND delete_flag=0
==> Parameters: 2024-03(String), 20240308(String), 0(Integer), 2(String), 0(String), 2024-03-14 22:20:09.0(Timestamp), 62169(Integer), 12(Integer), 2024-03-17 11:21:30.178(Timestamp), 62169(Integer), 62169(Integer), 90010(Long), 11(Integer)
<== Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1f057a7]
从日志可以发现后面更新时是从当前的会话中取的sqlSession,用的是同一个sqlSession,没有创建新的sqlSession,这是什么原因呢?
因为在调用的方法test()
加上@Transactional
注解后,其实省略了propagation
属性,而propagation
的默认值就是 Propagation.REQUIRED
,也就是说如果当前开启了事务,就不会创建新的事务。
其实上面的注解相当于
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
所以才有了上面的结果。