逐行解读Hikari连接池源码
发布时间:2022-08-02 11:29:55 所属栏目:云计算 来源:互联网
导读:写在前面 几年前,我最开始接触的数据库连接池是 C3P0,后来是阿里的 Druid,但随着 Springboot 2.0 选择 HikariCP 作为默认数据库连接池这一事件之后,HikariCP 作为一个后起之秀出现在大众的视野中,以其速度快,性能高等特点受到越来越多人青睐。 在实际
|
写在前面 几年前,我最开始接触的数据库连接池是 C3P0,后来是阿里的 Druid,但随着 Springboot 2.0 选择 HikariCP 作为默认数据库连接池这一事件之后,HikariCP 作为一个后起之秀出现在大众的视野中,以其速度快,性能高等特点受到越来越多人青睐。 在实际开发工作中,数据库一直是引发报警的重灾区,而与数据库打交道的就是 Hikari 连接池,看懂 Hikari 报警日志并定位异常原因,是实际工作中必不可少的技能! 本文以 Hikari 2.7.9 版本源码进行分析,带大家理解 Hikari 原理,学会处理线上问题! 源码地址:https://gitee.com/mirrors/hikaricp/tree/HikariCP-2.7.9/ 1、概念释义 在学习一项技术之前,需要先在宏观的层面去看到它的位置,比如我们今天学习的 HikariCP,它在什么位置? 以 Spring Boot 项目为例,我们有 Service 业务层,编写业务代码,而与数据库打交道的是 ORM 框架(例如 MyBatis),ORM 框架的下一层是 Hikari 连接池,Hikari 连接池的下一层是 MySQL 驱动,MySQL 驱动的下一层是 MySQL 服务器。理解了这个宏观层次,我们再去学习 Hikari 就不会学的那么稀里糊涂了。 其次,我们需要明白数据库连接池是干什么的? 简单来说,数据库连接池负责分配、管理和释放数据库的连接。有了数据库连接池就可以复用数据库连接,可以避免连接频繁建立、关闭的开销,提升系统的性能。它可以帮助我们释放过期的数据库连接,避免因为使用过期的数据库连接而引起的异常。 至于 Hikari,它是一个“零开销”生产就绪的 JDBC 连接池。库非常轻,大约 130 Kb。 2、配置使用 我们先来看一个线上 Hikari 连接池配置需要哪些参数。 复制 @Bean("dataSource") public DataSource dataSource() { HikariConfig cfg = new HikariConfig(); // 从池中借出的连接是否默认自动提交事务,默认开启 cfg.setAutoCommit(false); // 从池中获取连接时的等待时间 cfg.setConnectionTimeout(); // MYSQL连接相关 cfg.setJdbcUrl(); cfg.setDriverClassName(); cfg.setUsername(); cfg.setPassword(); // 连接池的最大容量 cfg.setMaximumPoolSize(); // 连接池的最小容量,官网不建议设置,保持与 MaximumPoolSize 一致,从而获得最高性能和对峰值需求的响应 // cfg.setMinimumIdle(); // 连接池的名称,用于日志监控,多数据源要区分 cfg.setPoolName(); // 池中连接的最长存活时间,要比数据库的 wait_timeout 时间要小不少 cfg.setMaxLifetime(); // 连接在池中闲置的最长时间,仅在 minimumIdle 小于 maximumPoolSize 时生效(本配置不生效) cfg.setIdleTimeout(); // 连接泄露检测,默认 0 不开启 // cfg.setLeakDetectionThreshold(); // 测试链接是否有效的超时时间,默认 5 秒 // cfg.setValidationTimeout(); // MYSQL驱动环境变量 // 字符编解码 cfg.addDataSourceProperty("characterEncoding", ); cfg.addDataSourceProperty("useUnicode", ); // 较新版本的 MySQL 支持服务器端准备好的语句 cfg.addDataSourceProperty("useServerPrepStmts", ); // 缓存SQL开关 cfg.addDataSourceProperty("cachePrepStmts", ); // 缓存SQL数量 cfg.addDataSourceProperty("prepStmtCacheSize", ); // 缓存SQL长度,默认256 // prepStmtCacheSqlLimit return new HikariDataSource(cfg); } 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 官方配置说明:https://github.com/brettwooldridge/HikariCP#configuration-knobs-baby 3、源码分析 1)分析入口 万事开头难,下载 Hikari 源码到本地后该从哪开始去看呢?不妨从下面两个入口去分析。 复制 // 1、初始化入口 new HikariDataSource(cfg) // 2、获取连接 public interface DataSource extends CommonDataSource, Wrapper { Connection getConnection() throws SQLException; } 1. 2. 3. 4. 5. 6. 7. 2)初始化分析 初始化分析主要有两部分工作,一是校验配置并且会矫正不符合规范的配置;二是实例化 Hikari 连接池。 复制 public HikariDataSource(HikariConfig configuration) { // 1、校验配置 并 矫正配置 configuration.validate(); configuration.copyStateTo(this); LOGGER.info("{} - Starting...", configuration.getPoolName()); // 2、创建连接池,注意这里设置了 fastPathPool pool = fastPathPool = new HikariPool(this); LOGGER.info("{} - Start completed.", configuration.getPoolName()); this.seal(); } 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 矫正配置 校验配置会直接抛异常,大部分坑来源于矫正配置这一步,这会使你的配置不生效。 复制 private void validateNumerics() { // maxLifetime 链接最大存活时间最低30秒,小于30秒不生效 if (maxLifetime != 0 && maxLifetime < SECONDS.toMillis(30)) { LOGGER.warn("{} - maxLifetime is less than 30000ms, setting to default {}ms.", poolName, MAX_LIFETIME); maxLifetime = MAX_LIFETIME; } // idleTimeout 空闲超时不能大于或者接近 maxLifetime,否则设置 0,禁用空闲线程回收 if (idleTimeout + SECONDS.toMillis(1) > maxLifetime && maxLifetime > 0) { LOGGER.warn("{} - idleTimeout is close to or more than maxLifetime, disabling it.", poolName); idleTimeout = 0; } // idleTimeout 空闲超时不能低于默认值 10 秒 (编辑:惠州站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
