@Resource private SqlSessionTemplate sqlSessionTemplate;
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 307 天前
finally 里的代码比 Thread 里的代码先运行
|
2
Bryant0814 OP @MoonWalker 这个 CountDownLatch 不是监控了子线程吗
|
3
cheng6563 307 天前
jdbc 不一定是线程安全的
|
4
Bryant0814 OP @cheng6563 结合我这个说一下
|
5
mango88 307 天前
看上去你的 batchInsert 并没有用到你提前存下的 connection
|
6
mango88 307 天前
还有打印异常最好不要吞掉全部的堆栈信息,根据堆栈报错信息结合源码看 你应该就清楚问题在哪了
|
7
sujin190 307 天前
不知道你用的数据库是啥,似乎没有数据库支持同一个连接多线程并发事务吧,否则必须每个线程一个连接单独事务你这等待回滚的意义在哪,多线程写同一个连接数据肯定损坏了就可能会出这个 connection closed 异常
|
8
wWjd5V5L0636B5YV 307 天前
找到原因了么?我这没发复现啊
|
9
bocharud 307 天前
如 #5 和 #7 说的那样, cacheTestMapper 变量内部的 connection 没有被带到 子线程中去.
没用过 mybatis, 不过按照你的代码来看, 你前面先拿出一个 connection 调用 setAutoCommit(false). 是否可以说明 mapper 和内部的 conn 和你这个 conn 相等. 那么可以认为它在类似于 thread_local 里面. 如果真是这样, 那么子线程的 mapper 获取不到 conn, 所以它说 connection closed |
10
yusheng88 305 天前 via Android
简单看下,存在两个问题
1. 没有做父子线程事务传递 2. 没有考虑任务数超出线程池上限 推测异常原因: 问题 2 导致一直 await ,直到连接被自动清理线程关闭 |