内容:多线程批量修改数据,1个线程操作报错,所有线程回滚。例子过于简单,主要靠理解
用到的技术:CountDownLatch计数器、AtomicInteger原子类
1.测试代码Controller
@Test
public void updateStudentWithThreadsWcc() {
//查询总数据
List<Student> allStudents = studentMapper.getAll();
// 线程数量
final Integer threadCount = 2;
//每个线程处理的数据量
final Integer dataPartionLength = (allStudents.size() + threadCount - 1) / threadCount;
// 创建多线程处理任务
ExecutorService studentThreadPool = Executors.newFixedThreadPool(threadCount);
CountDownLatch mainLatch = new CountDownLatch(1); // 用于判断主线程是否提交
CountDownLatch threadLatchs = new CountDownLatch(threadCount);
StudentTaskError taskStatus = new StudentTaskError(); // 用于判断子线程任务是否有错误
//用来判断是否全部成功a = b 就是全部成功
AtomicInteger a = new AtomicInteger(0);
AtomicInteger b = new AtomicInteger(0);
for (int i = 0; i < threadCount; i++) {
// 每个线程处理的数据
List<Student> threadDatas = allStudents.stream()
.skip(i * dataPartionLength).limit(dataPartionLength).collect(Collectors.toList());
studentThreadPool.execute(() -> {
studentService.updateStudents(threadDatas, threadLatchs,mainLatch,a,b,taskStatus);
});
}
try {
// 倒计时锁设置超时时间 30s
boolean await = threadLatchs.await(600, TimeUnit.SECONDS);
if (!await) { // 等待超时,事务回滚
taskStatus.setIsError();
}
} catch (Throwable e) {
e.printStackTrace();
taskStatus.setIsError();
}
mainLatch.countDown(); // 切换到子线程执行
studentThreadPool.shutdown(); //关闭线程池
System.out.println("主线程完成");
}
2.测试代码Service
void updateStudents(List<Student> students, CountDownLatch threadLatch,CountDownLatch mainLatch, AtomicInteger a,AtomicInteger b,StudentTaskError taskStatus);
2.测试代码impl
@Autowired
private DataSourceTransactionManager dataSourceTransactionManager;
@Autowired
private TransactionDefinition transactionDefinition;
public void updateStudents(List<Student> students, CountDownLatch threadLatch,CountDownLatch mainLatch, AtomicInteger a,AtomicInteger b,StudentTaskError taskStatus) {
TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
System.out.println("子线程:" + Thread.currentThread().getName());
//AtomicInteger a = new AtomicInteger(0);
try {
students.forEach(s -> {
int i1 = a.incrementAndGet();
log.info("线程名:{}==========================第:{}次===================>s.getId:{}", Thread.currentThread().getName(), i1,s.getId());
if(s.getId()==50) {
int aa = 1/0;
}
// 更新教师信息
String newTeacher = "TNO_" + new Random().nextInt(100);
s.setTeacher(newTeacher);
int aaa = studentMapper.update(s);
if(aaa >0){
log.info("线程名:{}==========================第:{}次===================>更新成功", Thread.currentThread().getName(), i1);
b.incrementAndGet();
}
});
} catch (Throwable e) {
log.info("线程名:{}==========================异常了",Thread.currentThread().getName());
taskStatus.setIsError();
} finally {
threadLatch.countDown(); // 切换到主线程执行
}
try {
mainLatch.await(); //等待主线程执行
} catch (Throwable e) {
taskStatus.setIsError();
}
// 判断是否有错误,如有错误 就回滚事务
/* log.info("总任务数:{},成功数:{}",a.get(),b.get());
if(a.get() !=b.get()){
//成功数,和任务书不一致 回滚
}*/
System.out.println(Thread.currentThread().getName()+"回滚前回滚前回滚前回滚前回滚前回滚前回滚前回滚前回滚前回滚前回滚前回滚前回滚前");
if (taskStatus.getIsError()) {
System.out.println(Thread.currentThread().getName()+"回滚回滚回滚回滚回滚回滚回滚回滚回滚回滚回滚回滚回滚回滚回滚回滚回滚回滚回滚回滚");
dataSourceTransactionManager.rollback(transactionStatus);
} else {
dataSourceTransactionManager.commit(transactionStatus);
}
}