本来不打算写这个题目的,因为 Druid 大多都是在 Spring 中使用的,它很多功能非常强大,但是对于 MySQL 性能测试中并不实用。但是由于特殊原因,还是得把这个拾起来。
在以前的性能测试的过程当中,我通常会采用 线程绑定连接 的方式进行测试,毕竟也用不到很多线程,再不济我就用 common-pool2 自己写一个。但是考虑到稳定性测试当中,持续时间非常久,自定义的功能缺少自愈能力,最终还是选择了使用已有成熟的 MySQL 连接池工具,经过几番对比,最后选择了 Druid 。
Druid简介
Druid连接池是阿里巴巴开源的数据库连接池项目,为监控而生,内置强大的监控功能,且监控特性不影响性能。Druid连接池功能强大,性能优越,使用占比高,是一款优秀的数据库连接池。
Druid连接池的主要特点包括:
Druid连接池的使用非常简单,只需几行代码即可配置和使用,是Java应用开发中不可多得的利器。
一个例子
static void main(String[] args) { // 创建 Druid 数据源 DruidDataSource dataSource = new DruidDataSource() // 配置数据库连接信息 dataSource.setUrl("jdbc:mysql://localhost:3306/funtester") dataSource.setUsername("root") dataSource.setPassword("funtester") // 获取数据库连接 Connection connection = dataSource.getConnection() // 执行 SQL 语句 Statement statement = connection.createStatement() def query = statement.executeQuery("select id, uid, create_time from record order by id desc limit 10;") while (query.next()) { println("id: ${query.getInt(1)}, uid: ${query.getInt(2)}, create_time: ${query.getTimestamp(3)}") } query.close() // 关闭数据库连接 statement.close() connection.close() }
控制台打印信息就不再展示了。
Druid配置项
上面例子中我们采取先创建 com.alibaba.druid.pool.DruidDataSource 对象,然后进行配置项设置。我们还有一种语法,如下:
// 配置Druid连接池属性 Properties properties = new Properties() properties.put("driverClassName", "com.mysql.cj.jdbc.Driver") properties.put("url", "jdbc:mysql://localhost:3306/funtester") properties.put("username", "root") properties.put("password", "funtester") properties.put("maxActive", "2") // 创建Druid连接池 dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties)
Druid连接池提供了非常丰富的配置参数,可以根据实际需求进行定制化配置,下面列出了一些常用的配置项:
基本配置:
初始化配置:
超时时间配置:
测试配置:
空闲连接回收配置:
其他配置:
以上是一些Druid连接池常用的配置参数,在配置时可以根据项目实际情况进行调整。比如对于长时间保持空闲状态的应用可以将maxIdle设置小一些,而对于并发量大的应用则需要将maxActive设置大一些。配置合理的连接池参数有利于提升应用的性能和稳定性。
并发
在性能测试过程中少不了要对连接池并发获取连接、归还连接。下面是演示的例子:
import com.alibaba.druid.pool.DruidDataSource import com.alibaba.druid.pool.DruidDataSourceFactory import com.funtester.frame.SourceCode import java.sql.Connection import java.util.concurrent.CountDownLatch import java.util.concurrent.ExecutorService import java.util.concurrent.Executors class DruidConcurrencyDemo extends SourceCode { private static DruidDataSource dataSource static { try { // 配置Druid连接池属性 Properties properties = new Properties() properties.put(DruidDataSourceFactory.PROP_DRIVERCLASSNAME, "com.mysql.cj.jdbc.Driver") properties.put(DruidDataSourceFactory.PROP_URL, "jdbc:mysql://localhost:3306/funtester") properties.put(DruidDataSourceFactory.PROP_USERNAME, "root") properties.put(DruidDataSourceFactory.PROP_PASSWORD, "funtester") properties.put(DruidDataSourceFactory.PROP_MAXACTIVE, "10") properties.put(DruidDataSourceFactory.PROP_INITIALSIZE, "3") properties.put(DruidDataSourceFactory.PROP_MAXWAIT, "5000") // 创建Druid连接池 dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties) } catch (Exception e) { e.printStackTrace() } } static void main(String[] args) throws InterruptedException { int threadCount = 4 // 模拟4个并发请求 CountDownLatch latch = new CountDownLatch(threadCount) ExecutorService executorService = Executors.newFixedThreadPool(threadCount) // 并发获取连接 for (int i = 0; i { try { Connection connection = dataSource.getConnection() // 模拟一些操作 Thread.sleep(1000) // 模拟1秒的操作时间 output("活跃连接数: " + dataSource.getActiveCount()) output("空闲连接数: " + dataSource.getPoolingCount()) connection.close() // 关闭连接 } catch (Exception e) { e.printStackTrace() } finally { latch.countDown() // 计数器减一 } }) } latch.await() // 等待所有线程执行完毕 executorService.shutdown() // 关闭线程池 // 获取连接池状态 output("活跃连接数: " + dataSource.getActiveCount()) output("空闲连接数: " + dataSource.getPoolingCount()) } }
控制台输出:
16:31:55:819 pool-2-thread-3 {dataSource-1} inited 16:31:57:353 pool-2-thread-1 活跃连接数: 2 16:31:57:353 pool-2-thread-2 活跃连接数: 2 16:31:57:354 pool-2-thread-1 空闲连接数: 0 16:31:57:354 pool-2-thread-2 空闲连接数: 0 16:31:58:365 pool-2-thread-3 活跃连接数: 2 16:31:58:365 pool-2-thread-4 活跃连接数: 2 16:31:58:365 pool-2-thread-3 空闲连接数: 0 16:31:58:366 pool-2-thread-4 空闲连接数: 0 16:31:58:369 main 活跃连接数: 0 16:31:58:370 main 空闲连接数: 2
如果你在设置中增加了 com.alibaba.druid.pool.DruidDataSourceFactory#PROP_MAXIDLE = "maxIdle";的话,控制台会提示:
main maxIdle is deprecated
该配置已经过期了。
FunTester原创专题推荐~