xk6-sql扩展问题:setup()阶段无法传递数据库连接
问题原因及解决方案
直接错误原因
你的代码存在两个核心问题:
- 访问路径错误:
setup()返回的是数据库连接对象db本身,但场景函数runtest1/runtest2中尝试访问data.db——这里的data就是setup返回的db对象,所以data.db是undefined,直接触发Cannot read property 'exec' of undefined报错。 - 连接无法跨进程复用:k6的
setup函数运行在主进程,而虚拟用户(VU)的场景函数运行在独立子进程中。xk6-sql的数据库连接是底层原生对象,无法被序列化传递到子进程,即便修正访问路径,直接使用data.exec()也会因连接失效报错。
修复方案
方案1:每次迭代创建/关闭连接(简单直观)
将数据库连接逻辑移到场景函数内部,确保每个VU进程使用独立连接:
修改main.js
提取连接字符串为全局常量,移除setup中返回连接的逻辑:
import sql from "k6/x/sql"; export { runtest1 } from "./runtest1.js"; export { runtest2 } from "./runtest2.js"; const testConfig = JSON.parse(open("./conf.json")); export const options = Object.assign( { insecureSkipTLSVerify: false, }, testConfig ); // 全局复用数据库连接字符串 export const DB_CONN_STR = "root:@tcp(127.0.0.1:3306)/testing"; export function setup() { // 如需初始化操作(如建表),可临时创建连接执行后关闭 const tempDb = sql.open("mysql", DB_CONN_STR); // 示例:检查cats1表是否存在(按需添加) // tempDb.exec(`CREATE TABLE IF NOT EXISTS cats1 (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255), breed VARCHAR(255), age INT)`); tempDb.close(); } export default function () { console.log("running test cases..."); }
修改runtest1.js
import sql from "k6/x/sql"; import { DB_CONN_STR } from "./main.js"; export function runtest1() { const db = sql.open("mysql", DB_CONN_STR); try { db.exec(`INSERT INTO cats1 (name, breed, age) VALUES ('test1-2', 'Doodle', 1)`); } finally { // 确保无论是否报错都关闭连接 db.close(); } }
修改runtest2.js
import sql from "k6/x/sql"; import { DB_CONN_STR } from "./main.js"; export function runtest2() { const db = sql.open("mysql", DB_CONN_STR); try { db.exec(`INSERT INTO cats1 (name, breed, age) VALUES ('test2-2', 'Doodle', 2)`); } finally { db.close(); } }
方案2:每个VU复用单个连接(性能更优)
如果希望每个VU在生命周期内只创建一次连接,可将连接逻辑放在模块级别(每个VU初始化时执行一次):
修改runtest1.js
import sql from "k6/x/sql"; import { DB_CONN_STR } from "./main.js"; // 每个VU初始化时创建一次连接 const db = sql.open("mysql", DB_CONN_STR); export function runtest1() { db.exec(`INSERT INTO cats1 (name, breed, age) VALUES ('test1-2', 'Doodle', 1)`); } // VU结束时关闭连接 export function teardown() { db.close(); }
runtest2.js做相同修改即可。
额外说明
- k6的
setup/teardown仅用于全局初始化/清理,不能传递不可序列化的对象(如数据库连接)。 - 每个VU拥有独立运行环境,必须使用自身的数据库连接,避免跨VU的资源竞争。
内容的提问来源于stack exchange,提问作者Zhang
相关产品推荐
相关产品推荐

