max-active 的作用:max-active是连接池中最大的活动连接数,其作用是防止一次性占用过多的连接资源,导致系统性能下降。
数据库连接配置文件中个参数的含义:
(1)name:表示你的连接池的名称也就是你要访问连接池的地址
(2)auth:是连接池管理权属性,Container表示容器管理
(3)type:是对象的类型
(4)driverClassName:是数据库驱动的名称
(5)url:是数据库的地址
(6)username:是登陆数据库的用户名
(7)password:是登陆数据库的密码
(8)maxIdle,最大空闲数,始终保留在池中的最大连接数,如果启用,将定期检查限制连接,超出此属性设定的值且空闲时间超过minEvictableIdleTimeMillis的连接则释放。设为0表示无限制。
(9)MaxActive,连接池的最大数据库连接数。设为0表示无限制。
(10)maxWait ,最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
1、连接池大小及性能选项
maxActive:最主要参数,配置连接池同时能维持的最大连接数,如果客户端理论上需要100个连接,则这个值设为100。设为0表示无限制。
maxIdle:如果客户端一段时间内不需要使用连接,如果一直把所有连接池中的所有连接都维持在活动状态是很浪费资源的,maxIdle这个选项告诉tomcat,如果客户端没有需求,那么最多维持maxIdle个空闲连接。
minIdle:和maxIdle类似,maxIdle告诉tomcat最多维持多少个空闲连接,minIdle告诉tomcat即使客户端没有需求,也要至少维持多少个空闲连接,以应对客户端的突发需求。
initialSize:连接池启动时要初始化多少个连接,即使客户端这是没有需求,也会初始化空闲连接。
maxWait:连接池出借连接的最长期限,单位是毫秒,比如设为10000ms,客户端从连接池获取(借出)一个连接后,10000毫秒没有归还(return),则连接池会抛出异常。设为-1表示无限制。
maxAge:连接池中一个连接的寿命,连接池初始化一个连接后,会记下初始化的时间,以后每次出借,或有客户端归还这个连接时,连接池会检查 当前时间 - 初始化时间 > maxAge,如果超过maxAge,连接池会删除这个连接。
2、连接池中最大的活动连接数 max-active 表示在连接池中允许同时存在的最大活动连接数。当达到这个最大值时,连接池将不再接受新的连接请求,直到有连接被释放,即可以从连接池中取出的连接数量是有限制的。这个参数的作用是可以限制连接池中的连接数量,防止连接过多导致资源浪费或者系统崩溃。
通过控制最大活动连接数,可以有效管理数据库连接的数量,避免因为连接过多导致系统性能下降或者数据库服务器负荷过高。
我们在讲多线程的时候说过,创建线程是一个昂贵的操作,如果有大量的小任务需要执行,并且频繁地创建和销毁线程,实际上会消耗大量的系统资源,往往创建和消耗线程所耗费的时间比执行任务的时间还长,所以,为了提高效率,可以用线程池。
类似的,在执行JDBC的增删改查的操作时,如果每一次操作都来一次打开连接,操作,关闭连接,那么创建和销毁JDBC连接的开销就太大了。为了避免频繁地创建和销毁JDBC连接,我们可以通过连接池(Connection Pool)复用已经创建好的连接。
JDBC连接池有一个标准的接口javax.sql.DataSource,注意这个类位于Java标准库中,但仅仅是接口。要使用JDBC连接池,我们必须选择一个JDBC连接池的实现。常用的JDBC连接池有:
- HikariCP
- C3P0
- BoneCP
- Druid
目前使用最广泛的是HikariCP。我们以HikariCP为例,要使用JDBC连接池,先添加HikariCP的依赖如下:
- com.zaxxer:HikariCP:2.7.1
紧接着,我们需要创建一个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时,把DriverManage.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代码的运行效率;可以配置连接池的详细参数并监控连接池。