项目场景:
项目中有个功能,需要从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();
}
});
}
本文探讨了在项目中使用多线程删除A表数据时,如何解决主线程查询数据不准确的问题。通过分析事务隔离级别,提出利用Spring的TransactionSynchronizationManager实现事务提交后自动更新B表的解决方案。
600

被折叠的 条评论
为什么被折叠?



