当前位置:网站首页>多线程保证单个线程开启事务并生效的方案
多线程保证单个线程开启事务并生效的方案
2022-07-30 09:26:00 【傻鱼爱编程】
我们开发的时候常常会遇到多线程事务的问题。以为添加了@Transactional注解就行了,其实你加了注解之后会发现事务失效。原因:数据库连接spring是放在threadLocal里面,多线程场景下,拿到的数据库连接是不一样的,即是属于不同事务。
Spring支持编程式事务和声明式事务,Spring提供的最原始的事务管理方式是基于TransactionDefinition、PlatformTransactionManager、TransactionStatus 编程式事务。
TransactionTemplate的事务管理是使用模板方法设计模式对原始事务管理方式的封装,因此我们也可以用TransactionTemplate管理事务。
今天我们就来谈下单个线程开启事务的方案:
1. 直接把线程方法单独提出,添加@Transactional注解
// 开启多线程的方法
public void testTransactional() throws ExecutionException, InterruptedException {
int inter = 3;
ExecutorService executorService = Executors.newFixedThreadPool(inter);
ThreadPoolExecutor poolExecutor = (ThreadPoolExecutor) executorService;
FutureTask[] integerFuture = new FutureTask[inter];
for (int i = 0; i < inter; i++) {
int finalI = i + 1;
integerFuture[i] = new FutureTask<>(() -> {
testTransactionalServiceZi.testTransactionalZi(finalI, "计算" + finalI);
System.out.println("多线程运行了---" + finalI);
return "业务执行成功";
});
poolExecutor.execute(integerFuture[i]);
}
for (int i = 0; i < inter; i++) {
System.out.println("integerFuture返回结果 = " + i + "==" + integerFuture[i].get());
}
}
// 单个线程调用,添加注解
@Transactional
public void testTransactionalZi(int num, String str) {
// 修改数据===1===
AdCourse adCourse = new AdCourse();
adCourse.setId(num);
adCourse.setName(str);
int i = adCourseMapper.updateById(adCourse);
// 修改数据===2===
adCourse.setId(num + 3);
adCourse.setName(str + 0);
int result = adCourseMapper.updateById(adCourse);
// 手动制造异常(事务会生效)
result = 1/0;
}2. 用TransactionTemplate管理事务
通过对源码的解读,TransactionTemplate封装的是PlatformTransactionManager。我们自己手写PlatformTransactionManager管理事务比较麻烦,所以通过TransactionTemplate来进行展示代码,如下:
@Service
public class TestTransactionalServiceImpl implements TestTransactionalService {
@Autowired
private TestTransactionalServiceZi testTransactionalServiceZi;
// 使用Template控制事务
@Autowired
private TransactionTemplate template;
public void testTransactional() throws ExecutionException, InterruptedException {
int inter = 3;
ExecutorService executorService = Executors.newFixedThreadPool(inter);
ThreadPoolExecutor poolExecutor = (ThreadPoolExecutor) executorService;
FutureTask[] integerFuture = new FutureTask[inter];
for (int i = 0; i < inter; i++) {
int finalI = i + 1;
integerFuture[i] = new FutureTask<>(() -> {
return template.execute(new TransactionCallback<String>() {
@Override
public String doInTransaction(TransactionStatus transactionStatus) {
testTransactionalServiceZi.testTransactionalZi(finalI, "计算666" + finalI);
System.out.println("多线程运行了---" + finalI);
return "业务执行成功";
}
});
});
poolExecutor.execute(integerFuture[i]);
}
for (int i = 0; i < inter; i++) {
System.out.println("integerFuture返回结果 = " + i + "==" + integerFuture[i].get());
}
}
}
// 需要调用的方法
public void testTransactionalZi(int num, String str) {
// 修改数据===1===
AdCourse adCourse = new AdCourse();
adCourse.setId(num);
adCourse.setName(str);
int i = adCourseMapper.updateById(adCourse);
// 修改数据===2===
adCourse.setId(num + 3);
adCourse.setName(str + 0);
int result = adCourseMapper.updateById(adCourse);
// 手动制造异常(事务会生效)
result = 1/(num-1);
}打印结果:第一个线程没有执行成功,出现了异常,数据也没有改变。

总结:以上两种方法可以保证多线程中单个线程事务的问题
边栏推荐
猜你喜欢
随机推荐
【深度学习】(问题记录)<对一个变量求梯度得到什么>-线性回归-小批量随机梯度下降
flowable工作流所有业务概念
Only after such a stage of development can digital retail have a new evolution
shell脚本
Jenkins 如何玩转接口自动化测试?
leetcode 剑指 Offer 10- I. 斐波那契数列
EViews 12.0 software installation package download and installation tutorial
Re20:读论文 What About the Precedent: An Information-Theoretic Analysis of Common Law
一个近乎完美的 Unity 全平台热更方案
PyQt5-用像素点绘制正弦曲线
通过构建一个顺序表——教你计算时间复杂度和空间复杂度(含递归)
leetcode 剑指 Offer 22. 链表中倒数第k个节点
69. Sqrt(x)x 的平方根
编译报错: undefined reference to `google::FlagRegisterer::FlagRegisterer解决方法
宝塔搭建DM企业建站系统源码实测
leetcode 剑指 Offer 57. 和为s的两个数字
北京突然宣布,元宇宙重大消息
2022 Hangzhou Electric Multi-School 2nd Game
Re21:读论文 MSJudge Legal Judgment Prediction with Multi-Stage Case Representation Learning in the Real
最长公共序列、串问题总结









