做压测的十个里有八个会栽在“连不上数据库”这个坎上。明明脚本逻辑简单得要命一个 JDBC Request 查点数据而已结果报错里清一色是No suitable driver found、Cannot create PoolableConnectionFactory整得人一头雾水。我刚接手 JMeter 那会儿也为这折腾过整整一个下午把lib目录翻了个底朝天最后才发现问题就出在驱动包的版本和放置位置上。这篇就专门说透一件事JMeter 连 MySQL 的驱动包配置加上怎么从零跑通一个数据库查询的实战链路。这篇内容不是什么高深理论就是实打实的操作经验。适合刚入坑性能测试、想用 JMeter 直接连 MySQL 造数据或者做数据校验的同学。我会把驱动包选型、jar 包放置位置、连接池配置、JDBC Request 写法、常见报错排查讲清楚。照着做完你会发现 JMeter 连数据库其实就是一层窗户纸捅破了就再也不会往里撞。1. 动手前先想清楚驱动包和数据库版本为什么要匹配1.1 先搞懂 JMeter 连数据库的原理才不会乱扔 jar 包JMeter 本身是用 Java 写的它连接 MySQL 走的是 JDBC 这个标准接口。类比一下JDBC 就是数据库世界的 USB 接口规范各家数据库厂商各自提供 U 盘驱动。MySQL 的驱动就是 MySQL Connector/J也就是一个 jar 包。JMeter 要读写 MySQL干的头一件事就是用Class.forName()加载这个驱动类然后通过DriverManager拿到连接。很多第一次弄的人会忽略一个问题驱动不是 JMeter 自带的也不是装了 MySQL 客户端就有的。你得自己把对应版本的 jar 包下载下来放到 JMeter 能扫描到的目录。这里我多说一句JMeter 启动时会扫描lib目录下的 jar 包并把它们加载到 classpath 里所以放完 jar 必须重启 JMeter 才生效。重启这事儿看着不起眼我身边就有人放完包不重启硬是排查了半小时“驱动加载不上”。1.2 MySQL Connector/J 版本别乱挑数据库版本说了算选驱动包版本的原则很朴素优先跟你 MySQL 服务器的大版本对上其次再看 JMeter 跑在哪个 JDK 上。常见的组合就这么两种情况。MySQL 5.x 数据库用mysql-connector-java-5.1.x.jar驱动类填com.mysql.jdbc.DriverURL 写jdbc:mysql://ip:3306/dbname。MySQL 8.x 数据库用mysql-connector-j-8.x.x.jar驱动类填com.mysql.cj.jdbc.DriverURL 建议写成jdbc:mysql://ip:3306/dbname?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue。这里有个坑必须单独拎出来说如果你 MySQL 是 8.x但图省事用了 5.1.x 的驱动包控制台会蹦出来一条Loading class com.mysql.jdbc.Driver. This is deprecated. The new driver class is com.mysql.cj.jdbc.Driver。有的脚本照样能跑但这属于老驱动硬兼容新模式连接参数、加密方式、时区处理都有差异不建议生产环境这么干。反过来MySQL 是 5.x你非要用 8.x 的新驱动有可能会因为服务端旧协议不支持新驱动的某个默认行为而报握手失败。所以我建议你把驱动版本和数据库版本一起确认清楚再动手别单看“最新版就是最好的”。1.3 jar 包不是扔进去就完事放置位置和依赖都要注意下载完驱动 jar 后把它拷贝到 JMeter 安装目录下的lib文件夹里。有的教程说放lib/ext其实常规做法是放lib就行lib/ext主要放 JMeter 自身的扩展组件。放完后记住重启 JMeter然后你可以临时加一个“JSR223 取样器”写一行log.info(Class.forName(com.mysql.cj.jdbc.Driver).getName());验证驱动类是不是真的被加载了。这一步看起来多余但能帮你把“驱动加载失败”和“配置写错”两类问题提前隔离开排查效率高很多。还要注意一件事新版 MySQL Connector/J 8.x 的包名是mysql-connector-j-xxx.jar它被拆成了模块化依赖有些情况下会出现“驱动类存在但连接时提示缺com.mysql.cj.protocol.a.NativeProtocol依赖”的诡异问题。这种一般是你只放了核心 jar没放它依赖的 protobuf 相关包。真碰上了最简单的办法是换用带依赖的完整包或者用 Maven 把mysql-connector-j的依赖树拉下来一起丢进lib。我自己的习惯是在本地建一个“JMeter 依赖包”文件夹专门放这些第三方 jar并在文件名上标注适配的数据库版本和日期。压测机环境经常不止一套多留个心眼能省很多重复排查时间。2. 核心配置逐项拆解JDBC Connection Configuration 不是随便填一填2.1 连接池变量名、URL、驱动类到底该怎么填配置元件“JDBC Connection Configuration”是整个数据库操作的核心入口但它放在测试计划里的位置很讲究。它不是放在“测试计划”根节点下就万事大吉而是建议放在线程组下。原因很简单每个线程组如果都配一份连接池配置并绑定不同的变量名不同线程组之间就各自独立不会互相抢连接。如果你把 JDBC Connection Configuration 放在测试计划根下它会被所有线程组共享并发一高连接数可能不够用还不好定位是哪个线程组把连接占满了。关键字段逐个说清楚Variable Name for created pool连接的变量名或者说池子的名字。这个东西特别像你给某个数据库连接串起的别名后面 JDBC Request 全靠它来绑定连接池。建议起得有意义一点比如db_pool_order别用a、b这种缩写。Database URLJDBC 连接串。这一行最容易写错常见错法是把jdbc:mysql://192.168.1.10:3306/testdb写成https://...或者漏掉端口更离谱的是在mysql后面加空格。8.x 数据库一定记住后面带上时区和 SSL 参数。JDBC Driver Class驱动类的完整限定名。5.x 是com.mysql.jdbc.Driver8.x 是com.mysql.cj.jdbc.Driver。手动填别幻想选个下拉框就自动帮你选对。Username/Password数据库账号密码。注意这里的密码是不会被加密的脚本文件别人拿到就能看到明文涉及敏感环境尽量用参数变量引进来。2.2 连接池里那一堆参数先搞懂 Max Wait 和连接数刚打开 JDBC Connection Configuration 的界面很多人会被右边那排英文吓到什么 Max Number of Connections、Max Wait、Time Between Eviction Runs。其实核心就两个其他保持默认也够用。Max Number of Connections连接池能创建的最大连接数。如果填 0JMeter 默认会按“线程数 1”来创建连接。这会导致一种结果你有 100 个并发线程数据库连接也快 100 条每个线程自己的连接是够用的但如果某个线程内的事务需要连续多个查询它就想占用同一个连接。连接池不足时新请求就会等积压下去会出现 “wait” 超时。所以压测场景我通常会按最大并发线程数乘以 1.5 来设置这个值留点余量。Max Wait拿不到连接时的最大等待毫秒数默认 10000 毫秒。意思是如果在 10 秒内拿不到连接就直接抛错不会无限等下去。如果你在“查不到数据”和“数据库假死”之间做区分这个字段的报错信息很有参考意义。等超时抛的是超时异常说明连接池满或者数据库响应慢如果抛的是拒绝连接那多半是网络或账号问题。Auto Commit这个默认改成 false 要慎重。如果设成 false你在一个线程里执行多条 update 语句它们会作为一个事务打包提交。但你只执行一条查询这个参数影响不大。新手建议保持 true免得执行完一条 update 没提交数据一直没变还以为是 SQL 写错了。Transaction Isolation事务隔离级别。不细究就直接默认除非你是在压测专门的隔离级别场景否则别乱动这个。这页配置里还有一个很容易被忽略的池子参数Pool Preload。勾选后连接池会在初始化阶段提前把连接建好而不是等第一个请求来了才慢慢建。压测刚开始那几秒数据库端往往会被瞬间蜂拥而至的连接请求打得措手不及勾上这个选项能明显缓解冷启动问题。我亲测过并发 200 的脚本不勾它前 5 秒数据库端会有大量 “establish connection” 的日志响应时间抖得很厉害勾上之后前几个事务平稳很多。2.3 驱动位置、classpath 与 JMeter 启动参数的兜底方案如果驱动类确认存在、配置看起来也对但 JMeter 还是报“Unable to load driver class”还有一个兜底方案可以试启动 JMeter 的时候手动把驱动 jar 加到 classpath。在启动脚本里加一个参数或者用bin/jmeter.sh或jmeter.bat前先设置环境变量JMETER_CLASSPATH把 lib 目录和驱动 jar 路径加进去。这么做不常规但有时候能解决某些第三方 jar 和 JMeter 内部类加载器的冲突。这种问题大多出现在 JMeter 以插件方式被 IDE 启动、或者用 Maven 跑 JMeter 脚本的场景里普通 GUI 场景不常见。真遇到类加载诡异问题先换一个干净的 JMeter 安装包试试这是成本最低的排查手段。我遇到过两次驱动加载不明原因失败重装 JMeter 后立刻正常到现在都说不清当初是哪个配置被搞脏了。3. 实战跑通从建测试计划到把查询结果拿出来用3.1 创建一个最小可用的数据库访问脚本这里我给你一套我常用的小白友好操作路径沿着做基本不会跑偏。先确认 MySQL 库里有可供测试的表比如user表字段有id、name、age。没有现成表的话先 SQL 建一张省得脚本跑通了却没数据可查。打开 JMeter创建一个线程组线程数先设 1循环次数设 1。调试阶段别一上来 100 并发报错信息根本看不过来。在线程组下添加“配置元件 → JDBC Connection Configuration”填入连接池变量名、URL、驱动类、账号密码。在线程组下添加“取样器 → JDBC Request”。运行脚本查看“察看结果树”里的请求结果。跑通一个最简单的查询后再逐步加并发、加断言、加参数化。我特别提醒一句调试阶段把“察看结果树”开着没问题但跑正式压测时务必关掉。这个监听器会把每个响应都存到内存里并发一高JMeter 自身的内存直接爆掉结果全乱套。JDBC Request 有几个字段需要重点解释。SQL Query里写SELECT * FROM user WHERE id ?下面会出现Parameter values和Parameter types两张输入框。Parameter values 填你想传入的参数值比如1Parameter types 填INTEGER。注意类型要写 JDBC 类型不是 MySQL 类型VARCHAR、INTEGER这种都可以。如果 SQL 里没有问号占位符Parameter values 留空就行。如果你要模拟两个或更多参数values 和 types 中间用英文逗号分隔JMeter 会按顺序匹配。这个顺序千万别弄反我见过有人把 values 填成1,2types 填成INTEGER,VARCHAR但 SQL 里第一个参数是字符串、第二个才是数字结果 curl 请求直接报类型转换错误。3.2 Statement 类型选不对SQL 执行结果天差地别JDBC Request 面板里Query Type这一栏默认是Select Statement它决定了 JMeter 怎么执行你写的 SQL。Select Statement执行普通查询返回 ResultSet。Update Statement执行 insert、update、delete返回受影响行数。Callable Statement调用存储过程。Prepared Select Statement/Prepared Update Statement预编译模式适合带参数的 SQL。新手最容易犯的错是在Update Statement里写INSERT语句提示执行成功但数据库里没数据变化。其实 JMeter 不会帮你强制检查语法类别你选错类型它也照样发但返回的结果处理和事务行为会有区别。比如你用 Select Statement 执行一条看似返回0的 INSERT它不会认真处理“受影响行数”你就很难断言是否真的插进去了。在需要反复执行同一条带参数的 SQL 的高并发场景我建议用Prepared Select Statement或Prepared Update Statement。预编译语句在数据库端有更高效的执行计划复用机制比每次拼接新 SQL 的执行效率高。压测里想看起来更接近真实业务行为也更推荐这种方式。真实业务系统十有八九用的都是预编译 SQL裸拼接字符串的反而少见。3.3 Variable names 和 Result variable name结果到底去哪了执行完查询结果存在哪这是很多人的盲点。JDBC Request 里有Variable names和Result variable name两个字段。先说Result variable name如果你填了resultListJMeter 会把整个结果集封装成一个org.apache.jmeter.protocol.jdbc.processor.ResultCollector对象并存到这个变量里。你在 JSR223 断言里能用vars.getObject(resultList)拿到它然后遍历每一行的字段。这招很强大适合做精细的数据校验。再说Variable names这是给单行结果起的列别名。举个例子你查询SELECT name, age FROM user WHERE id 1如果 Variable names 填name,age那查询结果里的第一列就存到${name}第二列存到${age}。你能在当前的取样器之后直接引用这两个变量比如拼进下游 HTTP 请求的 URL 参数里。这里有个细节如果查询返回多行而 Variable names 只填了两个那默认只会取第一行结果写入这两个变量后面几行并不会报错只是不赋值。要想取多行数据做分批压测你得靠 Result variable name 来遍历。我自己的习惯是简单场景用 Variable names复杂校验用 Result variable name两者不会互相替代。还有一个容易踩的坑风险在于变量遮蔽。如果两个不同作用的线程组里都用了相同的 Variable names比如都叫name后执行的线程组的值会覆盖先执行的。这在压测脚本复用、组合场景里特别坑。所以我建议每个线程组都配上前缀比如t1_name、t2_name宁可变量名长一点也别让数据串了。3.4 连接用完不关池子泄漏问题比你想的更严重JMeter 的连接池是在线程组执行期间创建、执行结束后自动关闭的。正常逻辑下你不用手动关。但有一种情况必须小心如果你在同一个线程组里通过“仅一次控制器”或“循环控制器”反复创建 JDBC Connection Configuration实际上同名变量会被重建。如果你在脚本里用了多个不同变量名的连接池执行完却没有把它们释放长时间压测会导致数据库端的连接全部被打满。JMeter 连接池的关闭依赖线程组执行结束但如果你用调试模式在 GUI 里反复点击“运行”上一次的线程组没有彻底结束连接可能还挂着。表现出来就是数据库执行show processlist;看到一堆来自 JMeter 机器的空闲连接越来越多。最直接的规避方法就是压测时长别太短、频繁手动启停真要反复调试就跑完一次后手动在数据库端 kill 掉残余空闲连接图省心的也可以直接重启 JMeter。你要是用的不是 GUI 而是命令行压测记住在压测脚本收尾处加一个“JSR223 后置处理器”也行但说实话不如直接保证线程组正常执行完来得可靠。连接池的释放是 JMeter 框架管的你只需保证不重复创建、不乱改变量名即可。4. 常见问题与排查技巧实录4.1 典型报错速查表建议直接截图存下来我在群里帮人诊断过不少 JMeter 连 MySQL 的报错下面这几种占了九成以上。报错关键字常见原因处理手法No suitable driver found for jdbc:mysql://...驱动 jar 没放对位置或 JDBC Driver Class 写错确认驱动在 lib 目录、重启 JMeter、核对驱动类名Cannot create PoolableConnectionFactory数据库地址不通、账号密码错、驱动类加载失败、连接受阻按 URL → 网络 → 账号 → 驱动的顺序排查Loading class com.mysql.jdbc.Driver is deprecated数据库或驱动版本不匹配用了旧驱动连接新数据库换成 8.x 驱动并改用com.mysql.cj.jdbc.DriverCommunications link failure网络不通或者数据库连接数被打满服务端拒连检查 IP/端口/防火墙数据库端看连接数Public Key Retrieval is not allowedMySQL 8.x 默认认证插件需要公钥检索URL 没放开URL 加allowPublicKeyRetrievaltrueThe server time zone value Öйú±ê׼ʱ¼ä时区识别乱码URL 加serverTimezoneAsia/ShanghaiPublic Key Retrieval这个错特别典型因为 MySQL 8.x 默认用的caching_sha2_password插件在首次连接时要求客户端先拉取服务端公钥如果 URL 里没有allowPublicKeyRetrievaltrueJMeter 侧的 JDBC 驱动会直接拒绝继续握手看起来像认证失败。这个参数对本地测试来说没有什么安全风险但如果是在公网或非信任网络连数据库就得分环境评估再决定要不要开。还有一类隐含问题如果你 Java 版本太老JDK 7 或以下新版 8.x 驱动可能直接因为 class 版本冲突加载不了。JMeter 4.0 以上通常强制要求 JDK 8所以别忽略 Java 版本这个底层条件。检查 JMeter 的启动日志如果驱动类加载那一行有UnsupportedClassVersionError那基本就是 JDK 太老升级 JDK 比折腾驱动快得多。4.2 排查顺序和独家避坑心得碰到数据库连接报错我建议按这个顺序来先看驱动能不能加载再看 URL 能不能连通再看账号密码能不能登录最后才怀疑 SQL 语法。这个顺序是我踩坑总结出来的倒过来排查会特别绕。你辛辛苦苦检查半天 SQL结果数据库账号压根没连上不是白折腾有一个快速定位的技巧别在 JMeter 里折腾先用数据库客户端比如 mysql 命令行或者随便一个图形客户端用同一个账号密码连一次。能连上说明账号和网络没问题问题出在 JMeter 配置这一侧连不上直接改密码或网络配置别碰 JMeter 脚本。这个技巧能拦截掉一半以上“假 JMeter 问题”。关于驱动加载还有一个很多人都不知道的细节JMeter 对lib目录下的 jar 是启动时全量扫描的如果你同时放了新旧两个版本的驱动 jar类名一旦冲突JMeter 可能加载到旧版本导致你明明配置了新版驱动类却报旧版特有的错。这时候lib目录越干净越好。只保留当前需要的那一个驱动包是避免这种妖孽问题的最好办法。另外建议你把连接池变量名、URL、驱动类这几个关键项做成 JMeter 用户自定义变量。这样做的好处有两个一是换环境、换库只需要改一处不用钻进每个取样器里改二是脚本提交到团队协作时其他人一眼就能看懂你连的是哪一套环境。我自己的模板里一般都会有DB_HOST、DB_PORT、DB_NAME、DB_USERNAME、DB_PASSWORD这几个变量几乎没有例外。最后分享一个我最近常用的做法如果压测环境允许优先在 JMeter 脚本里把连接池最大连接数显式设成一个明确值比如 50而不是填 0 让 JMeter 自由发挥。这样不管你怎么调并发数据库的连接使用量都在预期范围内不会出现压测完了、连接还在那里挂着把数据库拖垮的情况。别问我是怎么知道的反正有一次线上压测我图省事填了 0压完一看数据库连接数直逼几千运维差点没把我拉黑。写在最后一个小技巧就我自己的经验最节省时间的做法其实不是反复去试各个配置项而是把“驱动包版本 数据库版本 连接池变量名 查询类型”这四样东西先固定成一套标准组合。以后再遇到新环境先按标准组合跑一遍跑通了再改业务参数。如果标准组合都跑不通问题基本不在配置而在环境或者依赖上这时候直接把整台机器的 JMeter 面板截图发出来比在群里描述十几句管用得多。如果你之前被 JMeter 连 MySQL 折腾得够呛希望这篇能帮你把那些坑提前避开。照着上面的思路走一遍你大概率会发现自己再也不会在No suitable driver上卡上半个小时了。