有时候业务需求在一个方法中使用多线程来提高处理速度,那么采用多线程后整体事务如何该如何控制呢?
这里的思路是通过CountDownLatch以及volatile来配置使用。
CountDownLatch是一个程序计数器,可以用来表示当前有多少个线程。
volatile来保证共享变量的可见性和一致性:简单理解就是一个共享变量,当被某一个线程更改时,其他线程可以马上获取得到该变量修改后的属性。
然后来看具体代码实现:
package com.xx.service.resourceCenterMain.analysisInspCase;
import com.xx.mapper.targetLibraryMain.system.BaseSysMapper;
import com.xx.pojo.targetLibraryMain.system.BaseSys;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@RestController
public class ThreadTransaction {
// 因为使用了多数据源,因此项目采取了手动数据源配置
@Qualifier("targetLibraryMainTransactionManager")
@Autowired
DataSourceTransactionManager dataSourceTransactionManager;
// 这里是线程配置类
@Autowired
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@Resource
private BaseSysMapper baseSysMapper;
private volatile Boolean flag = true;
@RequestMapping("/tranMapping")
public void lala(){
// 放置线程状态
List<Boolean> flagList = new ArrayList<>();
// 子线程计数器(当前创建了两个线程)
CountDownLatch countDownLatch = new CountDownLatch(2);
// 主线程计数器(表示当前方法)
CountDownLatch main = new CountDownLatch(1);
try{
threadPoolTaskExecutor.execute(new Runnable() {
@Override
public void run() {
// 子事务
TransactionStatus transaction1 = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
try {
BaseSys baseSys = new BaseSys();
baseSys.setSysCode("11111");
// 插入数据
baseSysMapper.batchInsertBaseSys(baseSys);
//表示当前线程代码是否执行成功,后续会根据该list中的状态决定是否回滚事务
flagList.add(true);
// 计数器-1
countDownLatch.countDown();
// 阻塞当前线程,直到main计数器为0
main.await();
if (flag){
//所有线程运行成功 提交事务
dataSourceTransactionManager.commit(transaction1);
}else{
// 有线程未成功运行,回滚事务
dataSourceTransactionManager.rollback(transaction1);
}
} catch (InterruptedException e) {
countDownLatch.countDown();
dataSourceTransactionManager.rollback(transaction1);
}
}
});
// 事务2
threadPoolTaskExecutor.execute(new Runnable() {
@Override
public void run() {
// 子事务
TransactionStatus transaction2 = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
try {
BaseSys baseSys = new BaseSys();
baseSys.setSysCode("22222");
// 插入数据
baseSysMapper.batchInsertBaseSys(baseSys);
//表示当前线程代码是否执行成功,后续会根据该list中的状态决定是否回滚事务
flagList.add(false);
// 计数器-1
countDownLatch.countDown();
// 阻塞当前线程,直到main计数器为0
main.await();
if (flag){
//所有线程运行成功 提交事务
dataSourceTransactionManager.commit(transaction2);
}else{
// 有线程未成功运行,回滚事务
dataSourceTransactionManager.rollback(transaction2);
}
} catch (InterruptedException e) {
countDownLatch.countDown();
dataSourceTransactionManager.rollback(transaction2);
}
}
});
// 阻塞当前方法执行,直到countDownLatch计数器为0
countDownLatch.await();
for (Boolean bb : flagList) {
if (!bb){
// 判断所有子线程是否有运行失败的,有的话便通过volatile来通知到所有的子线程回滚事务
flag = false;
break;
}
}
main.countDown();
}catch (Exception e){
e.printStackTrace();
}
}
}
事务也可以采取以下代码处理:
创建一个事务管理器
@Component
public class TransactionalUntil {
@Resource
private DataSourceTransactionManager dataSourceTransactionManager;
/**
* 开启事务
*/
public TransactionStatus begin() {
TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
return transaction;
}
/**
* 提交事务
*/
public void commit(TransactionStatus transactionStatus) {
dataSourceTransactionManager.commit(transactionStatus);
}
/**
* 回滚事务
*/
public void rollback(TransactionStatus transactionStatus) {
dataSourceTransactionManager.rollback(transactionStatus);
}
}
然后注入该管理器后。直接在代码中采用事务管理器进行操作~