以下是 Hikari 连接设置
spring.datasource.hikari.connection-timeout=600000
spring.datasource.hikari.idle-timeout=300000
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.maximum-pool-size=15
spring.datasource.hikari.minimum-idle=5
下面是代码,分配线程池大小与最大连接数相同,将1M+记录列表分割10k并插入到数据库,使用mybatis批处理会话
ExecutorService executorService = Executors.newFixedThreadPool(15);
List<List<Employee>> listOfEmployees = new ArrayList<>(IntStream.range(0, totalEmployeeList.size()).boxed().collect(
Collectors.groupingBy(e -> e / 10000, Collectors.mapping(totalEmployeeList::get, Collectors.toList()))).values());
List<Callable<Void>> callables = listOfEmployees.stream().map(sublist ->
(Callable<Void>) () -> {
dao.insertEmployees(sublist);
return null;
}).collect(Collectors.toList());
try {
executorService.invokeAll(callables);
executorService.shutdown();
} catch (InterruptedException e) {
log.error("Exception in executing thread save", e);
}
批量会话代码 配置:
@Bean(value = "batchSqlSession")
@Autowired
public SqlSessionTemplate batchSqlSession(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);
}
道:
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) {
employeeList.stream().parallel().forEach(employee-> {
try{
employeeMapper.insertEmployees(employee);
} catch(Exception ex){
log.error("Exception - {} while inserting data {}",ex,employee.toString());
}
});
sqlSessionTemplate.flushStatements();
sqlSessionTemplate.clearCache();
}
当我运行这个时,我得到
由:org.apache.ibatis.exceptions.PersistenceException引起:
更新数据库时出错。 原因:org.springframework.jdbc.CannotGetJdbcConnectionException:失败
获取 JDBC 连接
错误可能存在于mapper/EmployeeMapper.xml中
错误可能涉及 com.fmr.qrit.datasync.mapper.EmployeeMapper.insertEmployees
执行更新时发生错误
原因:org.springframework.jdbc.CannotGetJdbcConnectionException:无法在
获取 JDBC 连接org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:84) 在 org.mybatis.spring.transaction.SpringManagedTransaction.openConnection(SpringManagedTransaction.java:80) 在 org.mybatis.spring.transaction.SpringManagedTransaction.getConnection(SpringManagedTransaction.java:67) 在 org.apache.ibatis.executor.BaseExecutor.getConnection(BaseExecutor.java:348) 在 org.apache.ibatis.executor.BatchExecutor.doUpdate(BatchExecutor.java:70) 在 org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117) 在 org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76) 在 org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:197) ... 22 更多 引起原因:java.sql.SQLTransientConnectionException: HikariPool-1 - 连接不可用,请求超时 30000ms(总计 = 10,活动 = 10,空闲 = 0,等待 = 6) com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:686) 在 com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:179) 在 com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:144) 在 com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:127) 在 org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource.getConnection(AbstractRoutingDataSource.java:213) 在 org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:160) 在 org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:118) 在 org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:81) ... 29 更多
我尝试将连接池大小从 10 增加到 15,然后将连接超时从 300000 增加到 600000,但同样的错误
我认为问题在于DAO方法中的employeeList.stream().parallel().forEach()语句。在内部,它拆分列表并并发执行,最终连接结果。这可能会导致过多的并发数据库连接请求,从而导致问题。
并行流非常适合 CPU 密集型操作,但不建议用于 I/O 密集型操作,例如数据库交互。
请尝试使用简单的 employeeList.stream().forEach 操作