hikari: minimum-idle: 5 maximum-pool-size: 200 max-lifetime: 50000 connection-timeout: 2000 idle-timeout: 15000
- 这篇博客主要记录如下报错的分析
Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:467)
我们写如下代码进行测试:
- case1:
快速请求两次,如上也就是会产生160个子线程请求往数据库存入数据。 这个时候部分不能请求成功的数据就会报如下错误:
----用户连接数查询
SELECT login_name,
ds.status,
Count(0) user_count
FROM Sys.dm_exec_requests dr WITH(nolock)
RIGHT OUTER JOIN Sys.dm_exec_sessions ds WITH(nolock)
ON dr.session_id = ds.session_id
RIGHT OUTER JOIN Sys.dm_exec_connections dc WITH(nolock)
ON ds.session_id = dc.session_id
WHERE ds.session_id > 50 and login_name='mingwang' and client_interface_name != 'Framework Microsoft SqlClient Da'
GROUP BY login_name,ds.status
ORDER BY user_count DESC
declare @student_no1 bigint
begin
set @student_no1 = 202106230003
select count(*) as insertNum from campus.table_a where student_no = @student_no1;
end
1). 如上我们可以看到 DB 链接量只申请到了126个,那么照理说存入DB的数据也应该有126条,那为什么少了5条了,那是因为当线程想hikri申请新加DB链接时, 短时间根本不能创建好这么多的请求,部分链接请求还在创建时,我们的线程获取DB链接设置的超时时间2000ms就已经到了,这个时候超时的线程已经报错了,所以就会有DB链接数多余实际插入数的情况。
2). 所以出现如上报错的第一种原因就是DB链接不能在大量请求到来时,及时创建对应的连接数量,而导致的请求连接超时报错。这个时候就可以根据service的实际情况去加大一点minimum-idle的设置。 - Case2:
同样是如上的代码,我们间隔性(保证是请求大于了最大链接数出的错,而不是不能及时创建报的错)的请求三次,就会有240个线程需要往DB插入数据
可以看到插入数据库的数量和DB的连接数量都是200. 所以每个DB链接都是被正常使用的,而还是会报如上的错就是因为,DB链接数已经达到了最大限制数,多余的请求线程只能因为超时请求不到链接而报错。 - Case3:
我们将case1中的事务线程睡眠取消,每个线程都可以快速跑完,如下我可以看到总线程只扩张到了10个,请求两次共计160个线程都是成功的。所以要避免将业务逻辑置于事务之中。同时也可以看出hikri也不是一味的去创建新链接,短时间能够处理完的也会优先使用已有链接(后续验证或有短时间排队),尽量减少平凡频繁的创建和销毁数据库连接。