# 数据库连接池
# 基本概念
与数据库建立连接(Connection)和断开连接是有时间开销的,而且在某一个时间点『同时』连接到数据库的客户端可能并没有想象中那么多,这就意味着数据库连接(Connection)对象是可以『重用』的。
数据库连接池的概念就是,预先准备好若干个与数据库建立好的连接,未来谁需要使用,就直接获取一个连接,在使用完毕后,再将该连接『还给』数据库连接池(而非真正断开连接)。如此就提高程序性能。
使用它们,对于 Connection 对象的管理工作,就完全转交到了它们的手里,Connection 对象不再由我们创建和销毁。
现在常见的数据库连接池有:DBCP2、C3P0、Druid 和 HikariCP(以出现先后顺序排序)。建议使用 Druid 和 HikariCP,原因见最后。
# 选择哪个数据库连接池
DBCP2 是 Appache 基金会下的项目,是最早出现的数据库连接池 DBCP 的第二个版本。
C3P0 最早出现时是作为 Hibernate 框架的默认数据库连接池而进入市场。
Druid 是阿里巴巴公司开源的一款数据库连接池,其特点在于有丰富的附加功能。
HikariCP 相较而言比较新,它最近两年才出现,据称是速度最快的数据库连接池。最近更是被 Spring 设置为默认数据库连接池。另外,Driud 的附加功能,HikariCP 基本也有。
# 不选择 C3P0 的原因:
C3P0 的 Connection 是异步释放。这个特性会导致释放的在某些情况下 Connection 实际上 still in use ,并未真正释放掉,从而导致连接池中的 Connection 耗完,等待状况。
Hibernate 现在对所有数据库连接池一视同仁,官方不再指定『默认』数据库连接池。因此 C3P0 就失去了『官方』光环。
C3P0 最后一次更新是在 2015 年,和最近蓬勃发展的 Druid 和 HikariCP ,以及持续更新的 DBCP2 相比,C3P0 显得不是那么“欣欣向荣”。
# 不选择 DBCP2 的原因:
相较于 Druid 和 HikariCP,DBCP2 没有什么特色功能/卖点。基本上属于 能用,没毛病
的情况,地位显得略有尴尬。
# Druid
Druid 阿里巴巴公司开源的一款数据库连接池。在功能、性能、扩展性方面,都超过它的先辈。
虽然晚于 Druid 的 HikariCP 数据库对外宣称是性能最快的数据库连接池,而且 Druid 方面也并未对此说法作出反驳。但一般看法是 HikariCP 数据库的性能对于 Druid 不具备压倒性优势。
# 简单使用
pom.xml
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> <!-- 8.0.21 --> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.20</version> </dependency>
有两种方式创建 Druid 数据库:通过 DruidDataSource 构造器,或者使用 DruidDataSourceFactory 工厂类。
使用 DruidDataSource 构造器
DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/scott?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai"); dataSource.setUsername("******"); dataSource.setPassword("******"); DataSource dataSource = DruidDataSourceFactory.createDataSource(properties); Connection connection = dataSource.getConnection(); System.out.println(connection == null ? "not connected" : "connected");
使用 DruidDataSourceFactory 工厂类
Properties properties = new Properties(); properties.setProperty("driver", "com.mysql.jdbc.Driver"); properties.setProperty("url", "jdbc:mysql://127.0.0.1:3306/scott?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false"); properties.setProperty("username", "******"); properties.setProperty("password", "******"); DataSource dataSource = DruidDataSourceFactory.createDataSource(properties); Connection connection = dataSource.getConnection(); System.out.println(connection == null ? "not connected" : "connected");
# 结合配置文件使用
配置文件:
jdbc.properties
driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/scott?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC username=root password=123456
从配置文件中加载配置信息,并创建数据库连接池:
代码:
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("jdbc.properties"); Properties properties = new Properties(); properties.load(is); DataSource dataSource = DruidDataSourceFactory.createDataSource(properties); // Druid Connection connection = dataSource.getConnection(); System.out.println(connection == null ? "not connected" : "connected");
# Druid 中的工具类:JdbcUtils
Druid 的 com.alibaba.druid.util 包下有若干工具类,其中 JdbcUtils 中提供了我们常见 JDBC 操作的封装。
其中,
增删改 SQL 操作,可以使用 .executeUpdate() 方法简化代码。
查询 SQL 操作,可以使用 .executeQuery() 方法简化代码。
另外,.close() 方法 .printResultSet() 也很有实用价值。
# HikariCP
HikariCP 是几个常见数据库连接池中出现的最晚的一个。它口号是“快速、简单、可靠”,官方宣传是性能最快的数据库连接池(貌似也没有其它方对此表示异议)。
# 简单使用
pom.xml
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> <!-- 8.0.21 --> </dependency> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>${hikaricp.version}</version> <!-- 3.2.0 --> </dependency>
HikariCP 专门定义了一个 HikariConfig 的配置类,用于创建 HikariCP 数据库连接池。
HikariConfig config = new HikariConfig(); config.setDriverClassName("com.mysql.cj.jdbc.Driver"); config.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/******?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false"); config.setUsername("******"); config.setPassword("******"); HikariDataSource dataSource = new HikariDataSource(config);
当然,因为某种原因,你也可以强行用上 Properties 对象,从 Properties 对象获得 HikariConfig 对象。
Properties properties = new Properties(); properties.setProperty("driverClassName", "com.mysql.cj.jdbc.Driver"); properties.setProperty("jdbcUrl", "jdbc:mysql://127.0.0.1:3306/******?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false"); properties.setProperty("username", "******"); properties.setProperty("password", "******"); DataSource dataSource = new HikariDataSource(new HikariConfig(properties)); // Druid Connection connection = dataSource.getConnection(); System.out.println(connection == null ? "not connected" : "connected");
这里需要注意的是,在配置数据库连接四大属性时,HikariCP 和其它数据库连接池用到了不同的单词。它使用到的是 driverClassName 和 jdbcUrl 。其它数据库连接池通常用的是 driver 和 url 。
# 配合配置文件使用
jdbc.properties
driverClassName=com.mysql.cj.jdbc.Driver jdbcUrl=jdbc:mysql://127.0.0.1:3306/scott?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false username=root password=123456
代码使用示例
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("jdbc.properties"); Properties properties = new Properties(); properties.load(is); DataSource dataSource = new HikariDataSource(new HikariConfig(properties)); Connection connection = dataSource.getConnection(); System.out.println(connection == null ? "not connected" : "connected");