JDBC 在性能测试中的应用
作者 | 黄炎帝
来源 | 阿里云云原生团队
前言
我们能否绕开 http 协议,直接测试数据库的性能?是否觉得从数据库中导出 CSV 文件来构造压测数据很麻烦?怎样在压测结束后做数据清理?能不能通过数据库中的插入(删除)记录对压测请求做断言?使用阿里云性能测试工具 PTS 可以轻松解决上述问题。
什么是 JDBC
JDBC(Java DataBase Connectivity,Java 数据库连接)是一种用于执行 SQL 语句的 Java API,可以为多种关系数据库提供统一访问,它由一组用 Java 语言编写的类和接口组成。JDBC 提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
简单地说,JDBC 可做三件事:与数据库建立连接、发送操作数据库的语句并处理结果。
JDBC 的设计原理
1 整体架构
JDBC 制定了一套和数据库进行交互的标准,数据库厂商提供这套标准的实现,这样就可以通过统一的 JDBC 接口来连接各种不同的数据库。可以说 JDBC 的作用是屏蔽了底层数据库的差异,使得用户按照 JDBC 写的代码可以在各种不同的数据库上进行执行。那么这是如何实现的呢?如下图所示:
JDBC 定义了 Driver 接口,这个接口就是数据库的驱动程序, 所有跟数据库打交道的操作最后都会归结到这里 ,数据库厂商必须实现该接口,通过这个接口来完成上层应用的调用者和底层具体的数据库进行交互。Driver 是通过 JDBC 提供的 DriverManager 进行注册的,注册的代码写在了 Driver 的静态块中,如 MySQL 的注册代码如下所示:
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
作为驱动定义的规范 Driver,它的主要目的就是和数据库建立连接,所以其接口也很简单,如下所示:
public interface Driver {
//建立连接
Connection connect(String url, java.util.Properties info)
throws SQLException;
boolean acceptsURL(String url) throws SQLException;
DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info)
throws SQLException;
int getMajorVersion();
int getMinorVersion();
boolean jdbcCompliant();
public Logger getParentLogger() throws SQLFeatureNotSupportedException;
}
作为 Driver 的管理者 DriverManager,它不仅负责 Driver 的注册/注销,还可以直接获取连接。它是怎么做到的呢?观察下面代码发现,实际是通过遍历所以已经注册的 Driver,找到一个能够成功建立连接的 Driver,并且将 Connection 返回,DriverManager 就像代理一样,将真正建立连接的过程还是交给了具体的 Driver。
for(DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
if(isDriverAllowed(aDriver.driver, callerCL)) {
try {
println(" trying " + aDriver.driver.getClass().getName());
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
// Success!
println("getConnection returning " + aDriver.driver.getClass().getName());
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
2 Connection 设计
通过上节我们知道数据库提供商通过实现Driver接口来向用户提供服务,Driver接口的核心方法就是获取连接。Connection是和数据库打交道的核心接口,下面我们看看它的设计方案。
通过观察设计图我们发现主要有两类接口:DataSource 和 Connection。下面我们逐一进行介绍。
DataSource
Connection getConnection() throws SQLException;
Connection getConnection(String username, String password)
throws SQLException;
}
Driver driver = getDriver();
String url = getUrl();
Assert.notNull(driver, "Driver must not be null");
if (logger.isDebugEnabled()) {
logger.debug("Creating new JDBC Driver Connection to [" + url + "]");
}
return driver.connect(url, props);
}
ConnectionPoolDataSource:连接池的实现,此数据源实现并不直接创建数据库物理连接,而是一个逻辑实现,它的作用在于池化数据库物理连接。
PooledConnection:配合 ConnectionPoolDataSource,由它获取一个池化对象 PooledConnection,再通过该 PooledConnection 间接获取到物理连接。
Statement:定义一个静态的 SQL 语句,数据库每次执行都需要重新编译,一般用于仅执行一次查询并返回结果的情形。
PreparedStatement:定义一个带参的预编译的 SQL 语句,下次执行时,会从缓存中取出遍以后的语句,而不需要重新编译一遍,适用于执行多次相同逻辑的 SQL 语句,当然它还有防 SQL 注入等功能,安全性和效率较高,使用比较频繁。对于性能测试来说,选择 PreparedStatement 最为合适。
CallableStatement:用来调用存储过程。
JDBC 在性能测试中的应用
背景
步骤
背景
步骤
地方使用${}引用即可。
背景
步骤