使用ExecutorService批量插入百万条数据时触发CannotGetJdbcConnectionException
解决ExecutorService+MyBatis批量插入时的CannotGetJdbcConnectionException异常
问题根源分析
- 线程数爆炸导致连接池耗尽:外部已使用15线程的固定线程池,DAO层又通过
parallel().forEach开启多线程,瞬间产生远超过连接池容量的并发连接请求,直接耗尽所有连接。 - 事务注解误用:
@Transactional添加在insertEmployees方法上,结合并行流会导致每个子线程都尝试获取新的事务连接,进一步加剧连接争抢;同时事务会持有连接直到方法结束,延长连接占用时间。 - MyBatis BATCH执行器未正确利用:循环单条插入而非调用批量插入方法,BATCH执行器的批量提交优势未发挥,反而增加了连接的持有时间和操作次数。
解决方案
1. 移除嵌套并行流,改用MyBatis批量插入
修改DAO层代码,删除parallel().forEach,直接调用Mapper的批量插入方法,减少连接占用时间和并发请求数:
public class EmployeeDAO { private final SqlSessionTemplate sqlSessionTemplate; private final EmployeeMapper employeeMapper; public EmployeeDAO(EmployeeMapper employeeMapper, @Qualifier("batchSqlSession") SqlSessionTemplate sqlSessionTemplate) { this.sqlSessionTemplate = sqlSessionTemplate; this.employeeMapper = sqlSessionTemplate.getMapper(EmployeeMapper.class); } // 移除@Transactional,避免事务绑定连接导致长时间占用 public void insertEmployees(List<Employee> employeeList) { try { // 调用批量插入Mapper方法 employeeMapper.batchInsertEmployees(employeeList); sqlSessionTemplate.flushStatements(); sqlSessionTemplate.clearCache(); } catch(Exception ex) { log.error("Exception while inserting batch data", ex); } } }
对应的Mapper接口增加批量插入方法:
public interface EmployeeMapper { void batchInsertEmployees(@Param("list") List<Employee> employeeList); }
Mapper XML编写批量插入语句:
<insert id="batchInsertEmployees"> INSERT INTO employee (id, name, ...) VALUES <foreach collection="list" item="emp" separator=","> (#{emp.id}, #{emp.name}, ...) </foreach> </insert>
2. 调整线程池与连接池的匹配策略
外部线程池的大小建议不要超过连接池最大连接数,同时预留少量连接应对突发情况,比如将线程池大小设为12(连接池max为15):
ExecutorService executorService = Executors.newFixedThreadPool(12);
3. 修正事务使用方式
如果需要全局事务控制,在调用线程池的上层方法添加@Transactional,而非在每个子任务方法中添加;如果不需要事务,直接移除@Transactional,让批量SqlSession自行管理连接。
4. 优化Hikari连接池配置,排查连接泄漏
开启Hikari的连接泄漏检测,定位是否有连接未被正确释放:
spring.datasource.hikari.leak-detection-threshold=20000 # 20秒检测泄漏
同时确保SqlSessionTemplate的配置正确,Spring会自动管理其连接的释放,避免手动操作不当导致泄漏。
验证效果
修改后,每个线程仅持有连接完成一次批量插入操作,连接占用时间大幅缩短,并发请求数控制在连接池容量范围内,即可解决无法获取JDBC连接的问题。
内容的提问来源于stack exchange,提问作者Pat
相关产品推荐
相关产品推荐

