性能测试除了测试Web应用,很多时候我们还需要直接对数据库进行压测,比如测试某个复杂查询的响应时间、考虑数据库连接池的性能等。LoadRunner提供了多种方式连接数据库,其中通过JDBC协议进行测试是非常灵活且强大的一种方式。湖南卓码软件测评有限公司(有CMA和CNAS双资质,可出具全国通用的软件测试报告)的工程师在实际项目中,常用这种方法来模拟大量用户并发访问数据库的场景。
选择协议Java Vuser
要对数据库进行JDBC测试,先需要在LoadRunner的Virtual User Generator(VuGen)中创建一个新脚本。协议的选择:需要选择 Java Vuser协议。这个协议允许我们直接编写Java代码,利用JDBC API和数据库进行交互,不是像Web测试那样录制HTTP请求。
配置环境加载JDBC驱动
创建脚本后,需要进行重要的环境配置-告诉LoadRunner去哪里找连接数据库的驱动包。
准备驱动Jar包:根据你的数据库类型(如MySQL、Oracle、SQL Server等),下载对应的JDBC驱动程序Jar包(如MySQL的mysql-connector-java-x.x.xx.jar,Oracle的ojdbcx.jar)。
设置Classpath:在VuGen脚本的Runtime Settings(运行时设置)中,找到 Classpath设置。点击Add File,将你下载的JDBC驱动Jar包添加进去。这一步非常重点,如果没有添加驱动,脚本运行时就会报ClassNotFoundException。
编写脚本代码
Java Vuser脚本主要包含 init、action、end 三个方法。我们需要在这里编写标准的Java JDBC代码。
一个通用的代码结构和思路,以MySQL为例:
java
import lrapi.lr;
import java.sql.*;
public class Actions
{
// 将连接对象定义为成员变量,在init中初始化,避免每次迭代都创建新连接
private Connection conn = null;
private Statement stmt = null;
private ResultSet rs = null;
// init方法:只执行一次,用于加载驱动和建立数据库连接
public int init() throws Throwable {
try {
// 1. 加载JDBC驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 获取数据库连接(URL, 用户名, 密码)
String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC";
String user = "testuser";
String password = "testpass";
conn = DriverManager.getConnection(url, user, password);
// 创建Statement对象
stmt = conn.createStatement();
lr.outputMessage("数据库连接成功");
} catch (Exception e) {
lr.errorMessage("数据库连接失败: " + e.getMessage());
return -1; // 初始化失败
}
return 0;
}
// action方法:根据迭代次数重复执行,这里是压测的实际内容
public int action() throws Throwable {
// 开始一个事务,用于记录SQL执行时间
lr.start_transaction("数据库查询");
try {
// 3. 编写并执行SQL语句
String sql = "SELECT * FROM user_info WHERE user_id = 1001";
rs = stmt.executeQuery(sql);
// 4. 处理结果集(可选,模拟应用处理数据的过程)
while (rs.next()) {
String userName = rs.getString("user_name");
// 可以将结果打印到日志或进行简单处理
// lr.outputMessage("查询到用户: " + userName);
}
// 关闭结果集
rs.close();
// 标记事务结束,状态自动判断
lr.end_transaction("数据库查询", lr.AUTO);
} catch (Exception e) {
lr.end_transaction("数据库查询", lr.FAIL);
lr.errorMessage("SQL执行失败: " + e.getMessage());
}
return 0;
}
// end方法:只执行一次,用于释放数据库资源
public int end() throws Throwable {
if (rs != null) try { rs.close(); } catch (Exception e) {}
if (stmt != null) try { stmt.close(); } catch (Exception e) {}
if (conn != null) try { conn.close(); } catch (Exception e) {}
lr.outputMessage("数据库连接已关闭");
return 0;
}
}
代码说明:
连接管理:数据库连接(Connection)的创建和关闭应放在 init 和 end 方法中。如果放在 action 里,每一次迭代都会创建和销毁连接,这不仅会消耗大量资源,也会导致测试结果失真,无法准确反映SQL语句本身的性能。
事务包裹:在action方法中,必须使用lr.start_transaction() 和 lr.end_transaction() 将SQL执行代码包裹起来。这样,LoadRunner的Controller在运行时就能精确记录这条SQL语句的执行耗时和通过率。
SQL参数化:如果要对不同的数据进行查询,可以使用LoadRunner的参数化功能。将SQL语句写成SELECT * FROM user_info WHERE user_id = '<userid>';,然后将 <userid> 替换为参数即可。
执行监控
脚本编写完成后,可以在VuGen中直接点击Run进行功能证实,保证脚本能正确连接数据库并返回数据。证实通过后,就可以将脚本放到Controller中,设置虚拟用户数、加载方法等,开始真正的性能测试了。