HikariCP数据库连接池 作者:马育民 • 2024-12-12 08:23 • 阅读:10000 # 介绍 HikariCP 号称是 **史上性能最好** 的数据库连接池,从15年推出以来,已经经受了广大应用市场的考验,并且成功地被SpringBoot2.0作为默认数据库连接池进行推广,在可靠性上面是值得信任的。其次借助于其代码量少,占用cpu和内存量小的优点,使得它的执行率非常高。最后,Spring配置HikariCP和druid基本没什么区别,迁移过来非常方便,这些都是为什么HikariCP目前如此受欢迎的原因。 ### 优化 Hikari相比起其它连接池的性能高了非常多,那么,这是怎么做到的呢?通过查看HikariCP官网介绍,对于HikariCP所做优化总结如下: 1. 字节码精简 :优化代码,编译后的字节码量极少,使得CPU缓存可以加载更多的程序代码; HikariCP在优化并精简字节码上也下了功夫,使用第三方的Java字节码修改类库Javassist来生成委托实现动态代理.动态代理的实现在ProxyFactory类,速度更快,相比于JDK Proxy生成的字节码更少,精简了很多不必要的字节码。 2. 优化代理和拦截器:减少代码,例如HikariCP的Statement proxy只有100行代码,只有BoneCP的十分之一; 3. 自定义数组类型(FastStatementList)代替ArrayList:避免ArrayList每次get()都要进行range check,避免调用remove()时的从头到尾的扫描(由于连接的特点是后获取连接的先释放); 4. 自定义集合类型(ConcurrentBag):提高并发读写的效率; 5. 关于Connection的操作:另外在Java代码中,很多都是在使用完之后直接关闭连接,以前都是从头到尾遍历,来关闭对应的Connection,而HikariCP则是从尾部对Connection集合进行扫描,整体上来说,从尾部开始的性能更好一些。 # 对比 [![](https://www.malaoshi.top/upload/0/0/1GWCmilpcjL.png)](https://www.malaoshi.top/upload/0/0/1GWCmilpcjL.png) # 依赖 ``` com.zaxxer HikariCP 3.1.0 ``` 或 ``` com.zaxxer HikariCP 4.0.3 ``` # 配置 HikariCP 所有时间相关的参数单位都为 ms。 详细的配置说明可参考官网文档:https://github.com/brettwooldridge/HikariCP ## 基本配置 |参数|默认值|描述| |---|---|---| |dataSourceClassName|none|驱动里面数据源的类名称;不支持|XA数据源,各数据源对应的数据源类名可参见|”2、数据源类名“| |jdbcUrl|none|连接|url;该参数与|dataSourceClassName|设置一个即可| |username|none|用户名| |password|none|密码| ## 常用配置 |参数|默认值|描述| |---|---|---| |autoCommit|true|连接返回连接池时,是否自动提交事务| |connectionTimeout|30000|从连接池获取连接的最大超时时间| |idleTimeout|60000|空闲连接存活的最大时间,当空闲连接数>minimumIdle|且|连接的空闲状态时间>idleTimeout|时,将把该连接从连接池中删除;只有当|minimumIdle|<|maximumPoolSize|时,该设置才生效;0|表示永不超时| |keepaliveTime||0|保持空闲连接可用的检测频率,单位:ms;0|表示不检测| |maxLifetime|1800000|连接存活的最大时间;0|表示没有限制| |connectionTestQuery|none|连接检测的查询语句;如果驱动支持|JDBC|4,强烈建议不要设置此参数| |minimumIdle|same|as|maximumPoolSize|最小空闲连接数;为了提高性能,建议不要设置此参数,使连接池为固定大小| |maximumPoolSize|10|最大连接数| |metricRegistry|none|该参数仅通过编程配置或|IoC|容器可用;该参数用于指定池使用的|Codahale/Dropwizard|MetricRegistry实例来记录各种指标。| |healthCheckRegistry|none|该参数仅通过编程配置或|IoC|容器可用;该参数用于指定池使用的|Codahale/Dropwizard|HealthCheckRegistry实例来记录健康信息。| |poolName|auto-generated|连接池名称| ## 不常用配置 |参数|默认值|描述| |---|---|---| |initializationFailTimeout|1|启动连接池时不能成功初始化连接,是否快速失败。>0|时,会尝试获取连接。如果获取时间超过指定时长(connectionTimeout|+|initializationFailTimeout),不会开启连接池,并抛出异常。=0|时,会尝试获取并验证连接。如果获取成功但验证失败则不开启池,但是如果获取失败还是会开启池。`<0`|时,直接启动连接池,不进行初始化连接尝试。| |isolateInternalQueries|false|是否在事务中隔离|HikariCP|自己的查询;autoCommit|为|false|时,该设置生效| |allowPoolSuspension|false|是否允许通过|JMX|挂起和恢复连接池;挂起时获取连接不会超时,知道连接池恢复| |readOnly|false|连接是否只读| |registerMbeans|false|是否开启|JMX| |catalog|driver|default|默认的数据库|catalog| |connectionInitSql|none|连接池初始化后执行的|SQL| |driverClassName|none|驱动类名;HikariCP|会尝试通过|jdbcUrl|来确定|driverClassName,但对一些老的驱动必须指定|driverClassName;可以忽略该配置除非报|"the|driver|was|not|found"|的错误。| |transactionIsolation|driver|default|默认的事务隔离级别| |validationTimeout|5000|连接检测的超时时间;必须大于|connectionTimeout,最小允许的值为|250| |leakDetectionThreshold|0|连接可以被借出多久;超过该时间将打印连接可能泄露的日志,最小允许的值为|2000,单位|ms| |dataSource|none|指定数据源;此参数仅通过编程配置或|IoC|容器可用,当设置此参数,dataSourceClassName|和所有|DataSource-|相关的属性将被忽略。| |schema|driver|default||默认的数据库|schema| |threadFactory||none||指定连接池用于创建线程的|java.util.concurrent.ThreadFactory|实例;此参数仅通过编程配置或|IoC|容器可用| |scheduledExecutor|none|指定连接池用于执行定时任务的|java.util.concurrent.ScheduledExecutorService|实例;此参数仅通过编程配置或|IoC|容器可用| # 例子 ``` package com.abc.demo.general.dbpool; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class HikariCPCase { private static Logger logger = LoggerFactory.getLogger(HikariCPCase.class); /** * 使用 dataSourceClassName */ @Test public void test1() { HikariConfig hikariConfig = new HikariConfig(); hikariConfig.setPoolName("HikariCP 连接池"); hikariConfig.setDataSourceClassName("oracle.jdbc.pool.OracleDataSource"); hikariConfig.addDataSourceProperty("user", "test"); hikariConfig.addDataSourceProperty("password", "123456"); hikariConfig.addDataSourceProperty("url", "jdbc:oracle:thin:@10.49.196.10:1521:test"); hikariConfig.setMaximumPoolSize(15); HikariDataSource hikariDataSource = new HikariDataSource(hikariConfig); Connection connection = null; try { connection = hikariDataSource.getConnection(); Statement st = connection.createStatement(); ResultSet rs = st.executeQuery("select * from v$version"); if (rs.next()) { logger.info(rs.getString(1)); } } catch (SQLException e) { e.printStackTrace(); } finally { close(connection); } //实际使用中一般是在应用启动时初始化数据源,应用从数据源中获取连接;并不会关闭数据源。 hikariDataSource.close(); } /** * 使用jdbc-url */ @Test public void test2() { HikariConfig hikariConfig = new HikariConfig(); hikariConfig.setPoolName("HikariCP 连接池"); hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver"); hikariConfig.setJdbcUrl("jdbc:mysql://10.49.196.11:3306/mydb?useUnicode=true&characterEncoding=UTF-8"); hikariConfig.setUsername("root"); hikariConfig.setPassword("123456"); hikariConfig.setMinimumIdle(2); hikariConfig.setMaximumPoolSize(10); HikariDataSource hikariDataSource = new HikariDataSource(hikariConfig); Connection connection = null; try { connection = hikariDataSource.getConnection(); Statement st = connection.createStatement(); ResultSet rs = st.executeQuery("select version()"); if (rs.next()) { logger.info(rs.getString(1)); } } catch (SQLException e) { e.printStackTrace(); } finally { close(connection); } //实际使用中一般是在应用启动时初始化数据源,应用从数据源中获取连接;并不会关闭数据源。 hikariDataSource.close(); } private static void close(Connection connection) { if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } ``` 参考: https://blog.csdn.net/weixin_59383491/article/details/131437532 https://www.cnblogs.com/wuyongyin/p/15560017.html 原文出处:http://malaoshi.top/show_1GWCn1prBwU.html