} while (timeout > 0L);
metricsTracker.recordBorrowTimeoutStats(startTime);
throw createTimeoutException(startTime);
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new SQLException(poolName + " - Interrupted during connection acquisition", e);
}
finally {
suspendResumeLock.release();
}
}
里面的代码虽然没有细究,但是从意思上看,应该是如果在hardTimeout时间内没有从连接池中获取到有效的连接,那就抛出异常,而抛出的正是日志中大量打印的那个异常。
==================================================================
从上面的源码中看,增加spring.datasource.hikari.connection-timeout
的值应该确实是有效的,最起码可以降低异常率,但是总连接数依然不足,所以看起来的现象应该是日志中的报错少了,但是系统会卡的要命。增加spring.datasource.hikari.maximum-pool-size
之后整个系统可用的最大连接数变多了,自然就不卡不报错了。
==========================================================================
为了验证我的想法,我写了一个demo
数据库相关配置文件:
#5个最小空闲连接,我把它理解为coreSize
spring.datasource.hikari.minimum-idle=5
#最大生命周期60s,测试用
spring.datasource.hikari.max-lifetime=60000
#一个连接空闲10s后,将会被回收
spring.datasource.hikari.idle-timeout=10
#连接池中的最大连接数
spring.datasource.hikari.maximum-pool-size=10
#获取连接的等待时长5s
spring.datasource.hikari.connection-timeout=5000
#判断连接是否有效
spring.datasource.hikari.connection-test-query=select 1
demo源码:
@SpringBootApplication(scanBasePackages = “com.example.juc.hikari”)
public class Main {
private static final Logger logger = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(Main.class, args);
DataSource dataSource = applicationContext.getBean(DataSource.class);
logger.info(“{}”, dataSource);
//先获取10个连接,就获取,不释放
int maxConnectionCount = 10;
List connections = new ArrayList<>();
for (int i = 0; i < maxConnectionCount; i++) {
try {
Connection connection = dataSource.getConnection();
connections.add(connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
//起一个新的
Thread thread = new Thread(() -> {
Connection connection = null;
do {
try {
//开始尝试获取连接
connection = dataSource.getConnection();
} catch (SQLException e) {
logger.error(“连接获取失败:[{}]”, e.getMessage());
}
//如果获取失败,就再来一次
} while (connection == null);
logger.info(“获取到新的连接了!”);
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
logger.info(“链接归还了!”);
}, “test”);
thread.start();
try {
logger.info(“主线程休眠10s”);
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//主线程休眠10秒之后,开始归还连接
connections.forEach(connection -> {
try {
connection.close();
logger.info(“归还了”);
} catch (SQLException e) {
e.printStackTrace();
}
});
}
}
先看结论:
. ____ _ __ _ _
/\ / _’ __ _ () __ __ _ \ \ \ \
( ( )___ | '_ | '| | ’ / _` | \ \ \ \
\/ _)| |)| | | | | || (| | ) ) ) )
’ || .__|| ||| |__, | / / / /
=|_|======|/=////
:: Spring Boot :: (v2.4.6)
21:42:11.251 [main ] INFO c.e.j.h.Main - Starting Main using Java 1.8.0_261 on DESKTOP-5R7UHQH with PID 15948 (D:\code\myCode\out\production\classes started by w123x in D:\code\myCode)
21:42:11.253 [main ] INFO c.e.j.h.Main - No active profile set, falling back to default profiles: default
21:42:12.086 [main ] INFO o.s.b.w.e.t.TomcatWebServer - Tomcat initialized with port(s): 8080 (http)
21:42:12.092 [main ] INFO o.a.c.h.Http11NioProtocol - Initializing ProtocolHandler [“http-nio-8080”]
21:42:12.093 [main ] INFO o.a.c.c.StandardService - Starting service [Tomcat]
21:42:12.093 [main ] INFO o.a.c.c.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.46]
21:42:12.164 [main ] INFO o.a.c.c.C.[.[.[/] - Initializing Spring embedded WebApplicationContext
21:42:12.165 [main ] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 873 ms
21:42:12.453 [main ] INFO o.a.c.h.Http11NioProtocol - Starting ProtocolHandler [“http-nio-8080”]
21:42:12.467 [main ] INFO o.s.b.w.e.t.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path ‘’
21:42:12.474 [main ] INFO c.e.j.h.Main - Started Main in 1.581 seconds (JVM running for 2.601)
21:42:12.475 [main ] INFO c.e.j.h.Main - HikariDataSource (null)
21:42:12.476 [main ] WARN c.z.h.HikariConfig - HikariPool-1 - idleTimeout is less than 10000ms, setting to default 600000ms.
21:42:12.476 [main ] INFO c.z.h.HikariDataSource - HikariPool-1 - Starting…
21:42:12.595 [main ] INFO c.z.h.HikariDataSource - HikariPool-1 - Start completed.
21:42:12.636 [main ] INFO c.e.j.h.Main - 主线程休眠10s
21:42:17.640 [test ] ERROR c.e.j.h.Main - 连接获取失败:[HikariPool-1 - Connection is not available, request timed out after 5003ms.]
21:42:22.647 [test ] ERROR c.e.j.h.Main - 连接获取失败:[HikariPool-1 - Connection is not available, request timed out after 5006ms.]
21:42:22.650 [main ] INFO c.e.j.h.Main - 归还了
21:42:22.650 [main ] INFO c.e.j.h.Main - 归还了
21:42:22.650 [main ] INFO c.e.j.h.Main - 归还了
21:42:22.650 [main ] INFO c.e.j.h.Main - 归还了
21:42:22.650 [main ] INFO c.e.j.h.Main - 归还了
21:42:22.650 [main ] INFO c.e.j.h.Main - 归还了
21:42:22.650 [main ] INFO c.e.j.h.Main - 归还了
21:42:22.650 [main ] INFO c.e.j.h.Main - 归还了
21:42:22.650 [main ] INFO c.e.j.h.Main - 归还了
21:42:22.650 [main ] INFO c.e.j.h.Main - 归还了
21:42:22.650 [test ] INFO c.e.j.h.Main - 获取到新的连接了!
21:42:22.650 [test ] INFO c.e.j.h.Main - 链接归还了!
总结
无论是哪家公司,都很重视高并发高可用的技术,重视基础,重视JVM。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。
最后我整理了一些面试真题资料,技术知识点剖析教程,还有和广大同仁一起交流学习共同进步,还有一些职业经验的分享。
] INFO c.e.j.h.Main - 链接归还了!
总结
无论是哪家公司,都很重视高并发高可用的技术,重视基础,重视JVM。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。
最后我整理了一些面试真题资料,技术知识点剖析教程,还有和广大同仁一起交流学习共同进步,还有一些职业经验的分享。
[外链图片转存中…(img-yp1l09ZY-1716575397276)]