@Resource private SqlSessionTemplate sqlSessionTmplate;
public void threadInsert(List<StudentVO> studentVOList) throws SQLException { long start = System.currentTimeMillis(); Connection cOnnection= sqlSessionTemplate.getConnection(); CacheTestMapper cacheTestMapper = sqlSessionTemplate .getSqlSessionFactory() .openSession() .getMapper(CacheTestMapper.class); try { //设置手动提交 connection.setAutoCommit(false); //先删除数据 cacheTestMapper.deleteStudentById(1L); //获取线程池 ExecutorService executorService = ExecutorUtil.getThreadPool(); //拆分数据创建任务 List<List<StudentVO>> lists = this.averageAssign(studentVOList, 5); Thread[] threads = new Thread[lists.size()]; //监控子线程执行完毕,再执行主线程,要不然会导致主线程关闭,子线程也会随着关闭 CountDownLatch countDownLatch = new CountDownLatch(lists.size()); for (int i = 0; i < lists.size(); i++) { List<StudentVO> list = lists.get(i); threads[i] = new Thread(() -> { try { //批量添加,mybatisPlus 中自带的 batch 方法 cacheTestMapper.batchInsert(list); } finally { countDownLatch.countDown(); } }); } for (int i = 0; i < lists.size(); i++) { executorService.execute(threads[i]); } //当子线程执行完毕时,主线程再往下执行 countDownLatch.await(); System.out.println("添加完毕"); connection.commit(); long end = System.currentTimeMillis(); System.out.println("多线程耗时:" + (end - start)); } catch (Exception e) { connection.rollback(); throw new RuntimeException("002 出现异常:" + e.getMessage()); } finally { connection.close(); } }
![]() | 1 MoonWalker 2024-02-01 16:16:39 +08:00 finally 里的代码比 Thread 里的代码先运行 |
2 Bryant0814 OP @MoonWalker 这个 CountDownLatch 不是监控了子线程吗 |
![]() | 3 cheng6563 2024-02-01 16:26:39 +08:00 jdbc 不一定是线程安全的 |
4 Bryant0814 OP @cheng6563 结合我这个说一下 |
![]() | 5 mango88 2024-02-01 16:43:36 +08:00 看上去你的 batchInsert 并没有用到你提前存下的 connection |
![]() | 6 mango88 2024-02-01 17:04:44 +08:00 还有打印异常最好不要吞掉全部的堆栈信息,根据堆栈报错信息结合源码看 你应该就清楚问题在哪了 |
![]() | 7 sujin190 2024-02-01 17:26:00 +08:00 不知道你用的数据库是啥,似乎没有数据库支持同一个连接多线程并发事务吧,否则必须每个线程一个连接单独事务你这等待回滚的意义在哪,多线程写同一个连接数据肯定损坏了就可能会出这个 connection closed 异常 |
8 wWjd5V5L0636B5YV 2024-02-02 10:15:59 +08:00 找到原因了么?我这没发复现啊 |
9 bocharud 2024-02-02 10:48:19 +08:00 如 #5 和 #7 说的那样, cacheTestMapper 变量内部的 connection 没有被带到 子线程中去. 没用过 mybatis, 不过按照你的代码来看, 你前面先拿出一个 connection 调用 setAutoCommit(false). 是否可以说明 mapper 和内部的 conn 和你这个 conn 相等. 那么可以认为它在类似于 thread_local 里面. 如果真是这样, 那么子线程的 mapper 获取不到 conn, 所以它说 connection closed |
![]() | 10 a5X77vajGRyLA2aF 2024-02-03 13:33:16 +08:00 via Android 简单看下,存在两个问题 1. 没有做父子线程事务传递 2. 没有考虑任务数超出线程池上限 推测异常原因: 问题 2 导致一直 await ,直到连接被自动清理线程关闭 |