☰
JMeter JDBC Connection Configuration配置详解:连接池与报错排查
2026/10/21 8:23:04 网站建设 项目流程

要做接口压测和日常接口测试,连接数据库基本上是绕不开的。很多刚接触Jmeter的人,一看到 JDBC Connection Configuration 这个配置元件就懵了,不知道它是干嘛的,也不知道和底下那个 JDBC Request 是什么关系,更不知道怎么配才能不报错。这篇文章就把这个配置元件彻底拆开,从面板上每个参数的含义,到连接池原理,再到怎么接上常见的开源数据库、怎么排查高频报错,一次讲清楚。

这篇内容适合两类人:一类是刚开始用Jmeter做接口测试,需要在压测前造数据、压测后清数据的人;另一类是已经能跑通HTTP接口脚本,但需要从数据库取值做参数化,或者用数据库结果做断言的人。JDBC Connection Configuration 本质上就是帮你管理数据库连接的公共配置,配好一次,整个测试计划里的 JDBC Request 都能共用,省心且稳定。

1. 为什么需要 JDBC Connection Configuration

先说个场景。你压测的是一个电商系统的下单接口,下单前你得给商品预留库存,下单后你要确认订单确实写进了库表,压测结束你还得把测试数据清干净。这三件事都离不开数据库操作,而Jmeter里执行SQL就靠 JDBC Request,但JDBC Request自己不会平白无故连上数据库,它需要一个已经初始化好的数据源。JDBC Connection Configuration 就是那个数据源的定义入口。

1.1 三个必须连库的经典场景

第一类是参数化数据源。HTTP接口的入参如果来自数据库,比如从用户表里随机取一批手机号去测登录接口,这时你只需要执行一条SELECT语句,把结果存成Jmeter变量,后续的HTTP请求直接用变量引用就行。我见过不少人直接写死手机号在CSV里,但测试环境和生产环境数据不一致,写死的方案维护成本很高,从库里实时取才是正路。

第二类是数据库断言。接口返回200不代表业务成功,订单号到底有没有落库,状态是不是预期值,这些只有查库才能确认。用 JDBC Request 查出结果,再用Jmeter的断言元件判断结果集里的字段,这才算闭环。

第三类是测试前后的数据准备和清理。批量压测往往需要重复执行同一份脚本,第一次跑完数据还在库里,第二次跑可能就触发了唯一索引冲突,或者库存被扣光了。每次跑前用SQL把数据重置到初始状态,跑完再做一次性清理,脚本能复用的关键就在这里。

1.2 JDBC Connection Configuration 和 JDBC Request 的分工

很多人第一次配就栽在分不清这两个元件。简单讲,JDBC Connection Configuration 是“建池子”,它负责把数据库连接池初始化好,里面有连接串、用户名、密码、连接池大小这些全局参数。JDBC Request 是“从池子里取连接执行SQL”,它本身不关心数据库地址和账号密码,只认一个东西,就是你在配置元件里填的那个 Variable Name。

所以配置元件可以只放一个,测试计划里加十个 JDBC Request 都行,这十个请求全部共用同一个连接池。反过来,如果你只加了 JDBC Request 而没加配置元件,或者配置元件里没填 Variable Name,执行的时候它会直接报错,提示找不到数据源。这个“名字对上号”的机制是理解整个配置的第一步,后面所有参数都建立在这个基础上。

2. JDBC Connection Configuration 面板逐项拆解

双击配置元件,看到的面板可以分成三块:连接池参数区、数据库连接区、事务隔离级别区。每一项都直接影响能不能连上、连上以后够不够用。

2.1 连接池参数区:变量名、超时与池大小

Variable Name 是这个连接池的唯一标识,建议起个一眼能认出来的名字,比如 DB_ORDER。这个变量名必须和 JDBC Request 里的 “Variable Name” 完全一致,区分大小写,多一个空格都不行。

Max Connections 是这个池子里最多能同时存在的物理连接数。它不是越大越好,因为数据库服务端也有最大连接数限制,Jmeter这边配100,数据库那边只允许50,多出来的连接会一直排队等。Max Wait 是拿不到连接时的最大等待时间,单位是毫秒,默认10000毫秒。超过这个时间还拿不到连接,Jmeter会直接报 “Cannot get connection” 之类的错误。Time Between Eviction Runs 是空闲连接回收的扫描间隔,Auto Commit 建议默认填 true,绝大多数场景不需要改。

这几个参数看起来是给数据库用的,其实决定了你能压多高的并发。如果压测线程数是100,同时每一个请求都要查一次库,那池子太小会导致请求堵在拿连接这一步,压出来的响应时间全是假的。所以这个参数不是抄个默认值就完事,得根据你的压测规模来算。

2.2 数据库连接区:URL、驱动类、账号密码

Database URL 是JDBC连接串,格式由数据库类型决定。以MySQL为例,常见写法是jdbc:mysql://127.0.0.1:3306/testdb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai。连接串里几个参数很关键:useSSL=false 是因为本地测试环境通常没有配置SSL证书,不关掉容易握手失败;serverTimezone 不指定,如果数据库时区和JVM默认时区不一致,日期字段会解析报错;allowPublicKeyRetrieval=true 是MySQL 8.0以上版本配合 caching_sha2_password 认证方式时常用到的参数,不然带密码连接可能直接连不上。

JDBC Driver Class 填驱动类的全限定名,MySQL 8.x 填com.mysql.cj.jdbc.Driver,早期版本填com.mysql.jdbc.Driver。填错一个字母都会报 ClassNotFound,很多人第一步就卡在这里。Username 和 Password 就不多说了,但有一点值得提醒:如果在压测脚本里硬编码了数据库密码,脚本在团队里流转时要用参数化方式引用,或者放到环境变量里,别直接明文到处转发。

数据库连接区还有一个 “Connection Validation” 区域,默认是不开启的。如果压测时间很长,空闲连接可能被数据库服务端主动断开,Jmeter再拿它执行SQL就会报连接失效。建议把 Test While Idle、Soft Minimum Evictable Idle Time 等选项打开,Jmeter会定时验证连接是否还活着,避免长时间压测过程中突然冒出一批连接失效的报错。

2.3 事务隔离级别区,什么时候需要改

事务隔离级别面板默认是 “Default”,也就是跟随数据库自己的默认设置,绝大多数情况不用动。只有你的业务里存在并发读写同一行数据,而且对数据一致性有严格要求时,才需要考虑调整。比如压测一个扣库存接口,同时还有校验订单状态的SQL,在同一个事务里需要保证读到的数据是稳定的,这时可以显式指定为 READ_COMMITTED 或 REPEATABLE_READ。但对Jmeter这种工具来说,脚本里更常见的做法是每条SQL独立提交,不太会手动控制多步事务,所以这块保持默认通常没问题。

3. 连接池原理与参数调优

前面参数都认识了一遍,但要想把配置调到位,你得知道连接池在Jmeter里到底是怎么工作的,不然出了问题只能瞎猜。

3.1 为什么Jmeter要用连接池而不是每条SQL新开连接

数据库连接是一个典型的“创建成本很高、使用成本很低”的资源。一次连接要经过TCP握手、认证、分配会话内存,耗时几十到几百毫秒。如果每条SQL都新建连接、用完就关,那压测脚本一半以上的时间都花在建立连接上,测试结果完全没有参考价值。

连接池的思路就是预先建好一批连接放在池子里,谁要用谁取,用完归还,省掉反复建立和销毁的开销。Jmeter在测试计划启动时会按配置初始化这个池子,第一个 JDBC Request 执行时连接已经准备好了,这就是为什么脚本里没有“显示连接数据库”这一步的原因。

3.2 参数计算:线程数、连接数和等待时间的关系

用一个具体例子来算。假设你开50个线程跑压测,每个线程每次迭代要执行一次 SQL 查询。JDBC Request 是同步执行的,也就是说这个线程在执行SQL期间占着一条连接不放。那么理想情况下,池子里至少要有50条连接,才能保证所有线程同时执行SQL时都有连接可用。

如果 Max Connections 只配了20,那50个线程同时来取连接,只有20个能拿到,剩下30个进入等待,等待时间受 Max Wait 控制。Max Wait 设成10000毫秒,如果10秒内前面20个连接有释放的,后面线程继续执行;如果一直没有释放,那30个请求直接报超时错误。这种情况下你看到的响应时间就会被严重拉长,因为每个请求都多等了好几秒。

反过来,也不能无脑把池子调大。假设数据库服务端配置了100个最大连接数,Jmeter这边配200,那Jmeter创建连接时也会失败,或者大量连接堆积在数据库端导致其他应用受影响。我个人的经验是,把 Max Connections 设成压测线程数的80%到100%,Max Wait 设成30000毫秒,给数据库在高负载下稍微慢一点留出缓冲。如果你用了BeanShell或JSR223脚本在同一个测试计划里打开多个JDBC Request,这个比例要适当调高一些,因为一个线程可能同时持有连接执行多条SQL。

3.3 长时间压测如何让连接池保持健康

跑30分钟以上的压测,最容易出现的情况是连接被数据库服务端主动断开,但池子里的对象不知道。这个问题的典型报错是 Communications link failure,或者 “Connection is not available, request timed out”。解决办法就是我前面提到的连接验证配置。在 Connection Validation 里勾选 Test While Idle,设置空闲验证间隔,Jmeter会周期性地对空闲连接发一个验证请求,最常见的验证方式是执行一个简单的查询,默认是SELECT 1。这样被断开的连接会在被重新使用前就被清理掉。

另外,连接池里的空闲连接回收也值得关注。Time Between Eviction Runs 设成60000毫秒,连接空闲超过一定时间就物理关闭,这样可以避免池子里全是数据库端已经断掉的死连接。这几个参数是压测脚本稳定性的隐形保障,很多人漏掉它们,压测跑到一半开始报错,还以为是数据库出问题了。

4. 实操:从驱动准备到JDBC Request跑通

到这一步,原理说完了,直接上手配。我以开源的关系型数据库为例,MySQL和PostgreSQL都走一遍,套路是一样的,换其他数据库只需要改驱动类名和连接串格式。

4.1 驱动Jar包放到哪里才对

驱动Jar包是个容易踩坑的地方。Jmeter需要能加载到JDBC驱动类,但jar包放的位置决定了它是只在当前测试计划生效,还是全局都能用。

如果你用的是Jmeter的lib目录,把mysql-connector-j-x.x.x.jar丢进$JMETER_HOME/lib/,重启Jmeter才能生效,这是最常用的方式。如果你不想动Jmeter安装目录,也可以直接把jar放到测试计划根节点的“Java Request”区域,通过 Add Jar 的方式引入,这样这个测试计划单独使用这个驱动,适合不同项目需要不同驱动版本的场景。

一个很常见的坑是放进了 lib/ext 目录,但没放 lib 目录,或者两个目录都有不同版本的jar,导致驱动类冲突,报 “Duplicate class” 或莫名其妙的方法签名错误。我的建议是只放 lib 目录,保持环境干净。下载驱动时注意版本和数据库版本匹配,MySQL 5.7用8.x驱动没问题,但反过来老驱动连新数据库就容易报 SSL 或认证问题。

4.2 配置MySQL数据库连接的完整参数

MySQL的配置面板填法如下。Database URL 我推荐使用:

jdbc:mysql://数据库地址:3306/库名?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8

JDBC Driver Class 填com.mysql.cj.jdbc.Driver。如果你的MySQL是5.x,可以填com.mysql.jdbc.Driver。

用户名和密码按实际填。补充一个经验,MySQL 8.0以上默认认证插件是 caching_sha2_password,如果连接串里没有 allowPublicKeyRetrieval=true,有些环境下会报 “Public Key Retrieval is not allowed”。加入这个参数能解决大部分本地连不上MySQL 8的问题。

配好后加一个 JDBC Request 验证连通性。JDBC Request 里 Query Type 选 Select Statement,SQL 写SELECT 1,添加一个 Listen,选择 View Results Tree 看结果。如果看到返回了一行,列名是1,值也是1,说明连接池和驱动都正常。

4.3 配置PostgreSQL数据库连接

PostgreSQL的套路类似,但参数完全不同。Database URL 填:

jdbc:postgresql://数据库地址:5432/库名

JDBC Driver Class 填org.postgresql.Driver。

PostgreSQL不需要像MySQL那样指定时区参数,但要注意PostgreSQL的驱动版本和数据库大版本匹配。PostgreSQL 9.x 用老驱动没问题,PostgreSQL 14以上建议用新驱动。驱动包通常是postgresql-version.jar,同样放到 lib 目录。

还有一个细节,PostgreSQL的JDBC URL里如果库名包含特殊字符,需要URL编码,正常库名没问题。JDBC Request 里Query Type 选 Select Statement,SQL写SELECT NOW()验证一下,返回值是当前时间,说明连接成功。

4.4 JDBC Request 的核心配置:查询类型和结果处理

JDBC Request 的 Query Type 下拉框里有 Select Statement、Update Statement、Callable Statement、Prepared Select Statement 等选项。很多人只知道选Select,但不同类型的SQL要用对应的类型,否则执行会报错。

普通查询用 Select Statement。增删改用 Update Statement。调用存储过程用 Callable Statement。Prepared Statement 则用于SQL里带?占位符的场景,配合变量传参。这里有个小技巧,如果你需要在SQL里使用Jmeter变量,比如SELECT * FROM user WHERE id = ${userId},Select Statement 直接用变量替换也能跑,但更规范的写法是用 Prepared Select Statement,把SQL写成SELECT * FROM user WHERE id = ?,然后在 Parameters 区域绑定?的值和数据绑定类型。这样不仅能避免特殊字符导致的SQL问题,也让脚本更清晰。

JDBC Request 执行SQL后,结果会存到变量里。默认情况下,列值变量名为<变量名>_<列序号>,比如DB_ORDER_1、DB_ORDER_2,如果变量名是DB_ORDER,第一列就是DB_ORDER_1。更直观的做法是在 JDBC Request 底部的 Variable Names 区域给列起个名字,比如要查订单号,SQL写SELECT order_no FROM orders WHERE id = 1,Variable Names 填order_no,后续引用就是${order_no_1}。注意这里的规律是变量名加下划线加行号,不是直接${order_no}。

4.5 把SQL结果接到HTTP请求参数上

跑通JDBC Request只是第一步,真正实用的是把数据库里的值传给后面的HTTP请求。比如从库里取一个有效商品ID,然后用它去发送下单请求。

先在 JDBC Request 里查询SELECT product_id FROM products WHERE status = 1 LIMIT 1,Variable Names 填product_id,因为只查一行一条数据,所以结果变量是product_id_1。再到HTTP请求的路径或Body里写${product_id_1},Jmeter执行时就会自动替换。

如果查询返回多行,比如要随机取一个用户手机号,SQL里用ORDER BY RAND() LIMIT 1,这样直接取出一行,避免在Jmeter里做随机行选择的麻烦。压测场景中我建议尽量让SQL自己返回恰好一条数据,脚本会简单很多。

5. 高频报错排查与实战技巧

配置数据库连接最耗费时间的不是填参数,而是报错后不知道从哪查起。我把这几年遇到的典型报错整理成一份速查思路,先把错误本质讲清楚,再给排查步骤。

5.1 最常见的报错:找不到驱动类和驱动冲突

报错里出现java.lang.ClassNotFoundException或者NoClassDefFoundError,基本就是驱动类名填错或驱动jar包没加载。先检查JDBC Driver Class 是不是完全匹配数据库类型,MySQL是com.mysql.cj.jdbc.Driver,PostgreSQL是org.postgresql.Driver。再检查jar包是否在 lib 目录且重启过Jmeter。

如果报错是Duplicate class或者某种方法签名不对,基本是 lib 和 lib/ext 里同时存在不同版本的驱动,把其中一个删掉,统一用一个版本。

5.2 连接建立失败:怎么看连接串和数据库状态

报错Cannot create PoolableConnectionFactory时,重点是看错误信息中间的冒号后面写了什么。如果是Communications link failure,要么是数据库地址不通,要么是端口被防火墙挡了,先在命令行用数据库客户端工具试着连一次,确认网络层没问题。

如果是Access denied for user,账密错或用户没有远程登录权限。有些数据库默认只允许本地登录,需要给测试账号授权远程访问。

连接串里参数有没有写对也值得检查,尤其是MySQL的时区参数serverTimezone,很多报错就是日期格式转换失败引起的。

5.3 连接池满了:请求等不到连接

报错Cannot get connection或者Connection is not available, request timed out,说明 Max Connections 太小,或者说 Max Wait 已经超时。解决办法是先把 Max Wait 调大,比如30000毫秒,同时调大 Max Connections,调到和压测线程数接近。如果已经调大到数据库能承受的上限还是报错,就得回头检查脚本里是不是有 JDBC Request 夹在循环里没及时释放,比如一个线程一次迭代执行了多条SQL,连接占用是翻倍的。

还有一种情况是测试计划里的 JDBC Request 执行了特别慢的SQL,把连接都占住了,要看数据库慢查询日志。

5.4 长时间压测才出现的连接失效问题

压测到一半突然大量报错Connection is closed或Broken pipe,大概率是空闲连接被数据库服务端回收了。打开 Connection Validation 的 Test While Idle,设置好验证间隔,让连接池主动探活。同时把连接串里和socket超时相关的参数检查一下,不要让它短于压测节奏。

5.5 实战技巧:用JDBC配合循环控制造数

最后分享一个很实用的玩法。在压测前需要批量造数据,用 JDBC Request 配合循环控制器可以一次插入大量记录。把JDBC Request放在循环控制器里,SQL写成INSERT INTO test_orders (id, user_name) VALUES (${__counter(TRUE,)}, 'test'),循环100次就是100条数据。要注意的是批量插入尽量用一条多条VALUES的SQL,别用循环一条条调用,否则Jmeter到数据库的往返次数太多,造数速度会非常慢。

另外,在写SQL时凡是涉及字符串类型的值,最好用 Prepared Statement 的变量绑定方式,不要直接拼接,否则遇到单引号等特殊字符容易出错,而且直接拼接变量会在压测时给数据库带来额外解析负担。

我个人在实际操作中的体会是,JDBC Connection Configuration 本身不算难,绝大多数人卡住都是因为没把“连接池是共享资源”这件事放在心上,参数要么抄默认,要么抄网上随便写的,结果一压测就暴露问题。花十分钟把连接池大小和压测线程数之间的关系算清楚,把连接验证打开,这套配置能让你在长时间压测里省掉很多麻烦。如果你是刚接触Jmeter,先从 MySQL 加一条 SELECT 1 跑通开始,再逐步加上真实业务SQL,一步一步来,比直接照搬大项目的配置要稳妥得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询