逐行解读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 秒 (编辑:惠州站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |