设为首页 加入收藏

TOP

面试官:Java 多线程怎么做事务控制?一半人答不上来。。(四)
2023-07-23 13:45:47 】 浏览:46
Tags:Java 程怎么
dentWithThreadsAndTrans() throws InterruptedException { //查询总数据 List<Student> allStudents = studentMapper.getAll(); // 线程数量 final Integer threadCount = 2; //每个线程处理的数据量 final Integer dataPartionLength = (allStudents.size() + threadCount - 1) / threadCount; // 创建多线程处理任务 ExecutorService studentThreadPool = Executors.newFixedThreadPool(threadCount); CountDownLatch threadLatchs = new CountDownLatch(threadCount); AtomicBoolean isError = new AtomicBoolean(false); try { for (int i = 0; i < threadCount; i++) { // 每个线程处理的数据 List<Student> threadDatas = allStudents.stream() .skip(i * dataPartionLength).limit(dataPartionLength).collect(Collectors.toList()); studentThreadPool.execute(() -> { try { try { studentService.updateStudentsTransaction(transactionManager, transactionStatuses, threadDatas); } catch (Throwable e) { e.printStackTrace(); isError.set(true); }finally { threadLatchs.countDown(); } } catch (Exception e) { e.printStackTrace(); isError.set(true); } }); } // 倒计时锁设置超时时间 30s boolean await = threadLatchs.await(30, TimeUnit.SECONDS); // 判断是否超时 if (!await) { isError.set(true); } } catch (Throwable e) { e.printStackTrace(); isError.set(true); } if (!transactionStatuses.isEmpty()) { if (isError.get()) { transactionStatuses.forEach(s -> transactionManager.rollback(s)); } else { transactionStatuses.forEach(s -> transactionManager.commit(s)); } } System.out.println("主线程完成"); } } @Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class}) public void updateStudentsTransaction(PlatformTransactionManager transactionManager, List<TransactionStatus> transactionStatuses, List<Student> students) { // 使用这种方式将事务状态都放在同一个事务里面 DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); // 事物隔离级别,开启新事务,这样会比较安全些。 TransactionStatus status = transactionManager.getTransaction(def); // 获得事务状态 transactionStatuses.add(status); students.forEach(s -> { // 更新教师信息 // String teacher = s.getTeacher(); String newTeacher = "TNO_" + new Random().nextInt(100); s.setTeacher(newTeacher); studentMapper.update(s); }); System.out.println("子线程:" + Thread.currentThread().getName()); }

由于这个中方式去前面方式相同,需要等待线程执行完成后才会提交事务,所有任会占用Jdbc连接池,如果线程数量超过连接池最大数量会产生连接超时。所以在使用过程中任要控制线程数量,

六、使用union连接多个select实现批量update

有些情况写不支持,批量update,但支持insert 多条数据,这个时候可尝试将需要更新的数据拼接成多条select 语句,然后使用union 连接起来,再使用update 关联这个数据进行update,具体代码演示如下:

update student,(
 (select  1 as id,'teacher_A' as teacher) union
 (select  2 as id,'teacher_A' as teacher) union
 (select  3 as id,'teacher_A' as teacher) union
 (select  4 as id,'teacher_A' as teacher)
    /* ....more data ... */
    ) as new_teacher
set
 student.teacher=new_teacher.teacher
where
 student.id=new_teacher.id

这种方式在Mysql 数据库没有配置 allowMultiQueries=true 也可以实现批量更新。

总结

  • 对于大批量数据库操作,使用手动事务提交可以很多程度上提高操作效率
  • 多线程对数据库进行操作时,并非线程数越多操作时间越快,按上述示例大约在2-5个线程时操作时间最快。
  • 对于多线程阻塞事务提交时,线程数量不能过多。
  • 如果能有办法实现批量更新那是最好

版权声明:本文为CSDN博主「圣心」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq273766764/article/details/119972911

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!J

首页 上一页 1 2 3 4 5 下一页 尾页 4/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇protobuf怎么处理java中的Object.. 下一篇Java在PDF中查找文本并为其添加超..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目