2022-06-08:JDBC连接池

我们在多线程一节说过,创建线程是一个昂贵的操作,如果有大量的小任务需要执行并且频繁地创建和销毁线程,实际上会消耗大量的系统资源,甚至创建和销毁线程耗费的时间比任务执行时间还长。所以为了提高效率,可以使用线程池。

类似的,在执行JDBC的增删改查操作时,如果每次操作都来一次打开连接、操作、关闭连接,那么创建销毁JDBC连接的开销就太大了。为了避免频繁创建和销毁连接,我们可以通过连接池(Connection Pool)复用已经创建好的连接。

JDBC连接池有一个标准接口javax.sql.DataSource,注意这个类位于Java标准库中,但仅仅是接口。要使用JDBC连接池,我们必须选择一个实现类,常用的JDBC连接池的实现有:

  • HikariCP
  • C3P0
  • BoneCP
  • Druid

目前使用最广泛的HikariCP,它的依赖是:

<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>2.7.1</version>
</dependency>

紧接着我们需要创建一个DataSource实例,这个实例就是连接池

HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
config.setUsername("root");
config.setPassword("password");
config.addDataSourceProperty("connectionTimeout", "1000"); // 连接超时:1秒
config.addDataSourceProperty("idleTimeout", "60000"); // 空闲超时:60秒
config.addDataSourceProperty("maximumPoolSize", "10"); // 最大连接数:10
DataSource ds = new HikariDataSource(config);

注意创建DataSource也是一个非常昂贵的操作,所以通常DataSource实例总是作为一个全局变量存储,并贯穿整个应用程序的生命周期。

有了连接池之后要如何使用呢?和之前的代码类似,只是获取Connection时,把DriverManager.getConnection()改为ds.getConnection()

try (Connection conn = ds.getConnection()) { // 在此获取连接
    ...
} // 在此“关闭”连接

通过连接池获取连接时,并不需要指定JDBC的相关URL、用户名、口令等信息,因为这些信息已经存储在了连接池内部了(创建HikariDataSource时传入的HikariConfig持有这些信息)。一开始,连接池内部并没有连接,所以,第一次调用ds.getConnection(),会迫使连接池内部先创建一个Connection,再返回给客户端使用。当我们调用conn.close()方法时(在try(resource){...}结束处),并非真正“关闭”连接,而是释放到连接池中,以便下次获取连接时直接返回

因此,连接池内部维护了若干个Connection实例,如果调用ds.getConnection(),就选择一个空闲连接,把它标记为“正在使用”然后返回,如果对Connection调用close(),那么就把连接再次标记为“空闲”从而等待下一次调用。这样一来,我们就通过连接池维护了少量连接,但却可以频繁执行大量的SQL语句

通常连接池提供了大量参数可以配置,例如,维护的最小、最大活动连接数,指定一个连接在空闲一段时间之后自动关闭等,需要根据应用程序的负载合理地配置这些参数。此外,大多数连接池都提供了详细的实时状态以便进行监控。

 

小结

数据库连接池是一种复用Connection组件,它可以避免反复创建新连接,提高JDBC代码的运行效率。

可以配置连接池的详细参数监控连接池

 

posted @ 2022-06-08 16:34  ShineLe  阅读(14)  评论(0)    收藏  举报