主线程中delete数据,子线程中select发现数据没变

本文探讨了在项目中使用多线程删除A表数据时,如何解决主线程查询数据不准确的问题。通过分析事务隔离级别,提出利用Spring的TransactionSynchronizationManager实现事务提交后自动更新B表的解决方案。

项目场景:

  项目中有个功能,需要从A表中删除一些数据,然后在B表中更新目前A表的实时数据条数。
  出于性能考虑,另开了多个线程删除A表,等A表操作完后,主线程再更新B表。
  
  伪代码如下:

public void method() {
	// 从A表中删除一些数据
	deleteByMultiThread();
	// 更新表B
	updateB();
}

public void updateB(){
	// 查询A表中现有的数据条数
	int count = selectCountFromA();
	// 更新B表中,对A表条数的计数
	updateDataInB(count);
}

/**
  * 从表A删除数据
  * 实际业务中,用了多个线程操作,CountDownLatch计数等待所有子线程操作完成
  * 这里简化为一个线程,但并不影响此问题
  */
public void deleteByMultiThread(){
	new Thread(){
		@Override
		public void run() {
			deleteA();
		};
	}.start();
}

问题描述:

  在实际调试过程中,发现updateB方法中的selectCountFromA方法,获取到的数量经常不对。比如,A表原有100条数据,在deleteByMultiThread方法中删除了10条,selectCountFromA方法获取到的数量还是100条,而不是预期中的90条。


原因分析:

  由于开启了子线程来删除A表,其与主线程中查询B表的sql属于不同的事务。在主线程查询B表时,删除A表的事务可能还没有提交,所以B表查询到的还是旧数据。
  参考情形如下:

子线程事务主线程事务
begin;begin;
delete A;
selectCountFromA;
updateDataInB;
commit;commit;

解决方案:

  既然是子事务还没提交引起的,那么让主线程在子线程事务提交后再执行即可。
  在spring中,可以使用TransactionSynchronizationManager注册一个TransactionSynchronization,然后在afterCommit里执行我们的后续代码,这样就能100%确保我们的后续逻辑是在当前事务被commit后才执行的。

TransactionSynchronizationManager可以简单的理解为:使用TreadLocal记录事务的一些属性,用于应用扩展同步器的使用,在事务的开启,挂起,提交等各个点上回调应用的逻辑

伪代码如下:

public void method() {
	// 从A表中删除一些数据
	deleteByMultiThread();
	TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
		@Override
		public void afterCommit() {
			// 更新表B
			updateB();
		}
	});
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值