什么是 JDBC
JDBC(Java DataBase Connectivity,Java 数据库连贯)是一种用于执行 SQL 语句的 Java API,能够为多种关系数据库提供对立拜访,它由一组用 Java 语言编写的类和接口组成。JDBC 提供了一种基准,据此能够构建更高级的工具和接口,使数据库开发人员可能编写数据库应用程序。
简略地说,JDBC 可做三件事:与数据库建设连贯、发送操作数据库的语句并处理结果。
JDBC 的设计原理
整体架构
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());
}
}
Connection 设计
通过上节咱们晓得数据库提供商通过实现 Driver 接口来向用户提供服务,Driver 接口的外围办法就是获取连贯。Connection 是和数据库打交道的外围接口,上面咱们看看它的设计方案。
通过观察设计图咱们发现次要有两类接口:DataSource 和 Connection。上面咱们逐个进行介绍。
DataSource
间接看源码,如下所示,发现它的外围办法居然和 Driver 一样,也是获取连贯。那为什么还要 DataSource 呢?Driver 自身不就是获取连贯的吗?上面咱们就看看 DataSource 到底是怎么获取连贯的。
public interface DataSource extends CommonDataSource, Wrapper {
Connection getConnection() throws SQLException;
Connection getConnection(String username, String password)
throws SQLException;
}
然而咱们发现 JDBC 只定义了 DataSource 的接口,并没有给出具体实现,上面咱们就以 Spring 实现的 SimpleDriverDataSource 为例,来看看它是怎么做的,代码如下所示,发现 DataSource 的 getConnection(…)办法,最初居然还是交由 driver.connect(…)去真正建设连贯。所以又回到最开始咱们所形容的,Driver 才是真正的与数据库打交道的接口。
protected Connection getConnectionFromDriver(Properties props) 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);
}
那么问题来了,为什么还须要 DataSource 这样的接口,岂不多此一举么?显然不会。DataSource 是加强版的 Driver。它将外围的建设连贯的过程交由 Driver 执行,而对于建设缓存,解决分布式事务和连接池等看似与建设连贯无关的事件本人来解决。如类的设计图所示,以 PTS 应用的 Druid 连接池为例:
ConnectionPoolDataSource:连接池的实现,此数据源实现并不间接创立数据库物理连贯,而是一个逻辑实现,它的作用在于池化数据库物理连贯。
PooledConnection:配合 ConnectionPoolDataSource,由它获取一个池化对象 PooledConnection,再通过该 PooledConnection 间接获取到物理连贯。
显然,通过连接池咱们能够从连贯的治理中抽身,进步连贯的利用效率,也能晋升压力机的施压能力。
Statement 设计
建设连贯之后,用户可能要开始写 SQL 语句,并且交由数据库去执行了。这些是通过 Statement 来实现的。次要分为:
Statement:定义一个动态的 SQL 语句,数据库每次执行都须要从新编译,个别用于仅执行一次查问并返回后果的情景。
PreparedStatement:定义一个带参的预编译的 SQL 语句,下次执行时,会从缓存中取出遍当前的语句,而不须要从新编译一遍,实用于执行屡次雷同逻辑的 SQL 语句,当然它还有防 SQL 注入等性能,安全性和效率较高,应用比拟频繁。对于性能测试来说,抉择 PreparedStatement 最为适合。
CallableStatement:用来调用存储过程。
ResultSet 设计
JDBC 应用 ResultSet 接口来承接 Statement 的执行后果。ResultSet 应用指针的形式(next())来逐条获取检索后果,当指针指向某条数据时,用户能够自在的抉择获取某一列的数据。PTS 通过将 ResultSet 转化成 CSV 文件,辅助用户以一条 SQL 语句,结构简单的压测数据。
JDBC 架构总结
通过下面的介绍咱们发现,JDBC 的设计还是层次感明显的。
(1)Driver 和 DriverManager 是面向数据库的,设计了一套 Java 拜访数据的标准,数据库厂商只须要实现这套标准即可;
(2)DataSource 和 Connection 是面向应用程序开发者的,它们不关怀 JDBC 具体是如何跟数据库进行交互的,通过对立的 DataSource 接口就能够拿到 Connection,用户的数据操作都能够通过这个 Connection 来实现了;
(3)Statement 承载了具体的 SQL 命令,用户能够定义不同的 Statement 来向数据库发送指令;
(4)ResultSet 是用来承载 SQL 命令的执行后果。
至此,实现了 加载驱动 -> 建设连贯 -> 执行命令 -> 返回后果 这样的和数据库交互的整个过程。如果把这个过程灵便的嵌入到 PTS 性能测试中,便能够解决前言提到的各种问题。
JDBC 在性能测试中的利用
数据库性能测试
背景
大多数对数据库的操作都是通过 HTTP、FTP 或其余协定执行的,然而在某些状况下,绕开两头协定间接测试数据库也很有意义。例如咱们心愿不触发所有相干查问,而只测试特定 high-value 查问的性能;验证新数据库在高负载下的性能。2. 验证某些数据库连接池参数,例如最大连接数 3. 节省时间和资源。当咱们想要优化 SQL 时,批改代码中的 SQL 语句和其余数据库操作十分繁琐,通过 JDBC 压测,咱们能够防止侵入代码,集中精力在 SQL 调优上。
步骤
1、创立场景。咱们在 PTS 控制台的【压测核心】->【创立场景】中创立 PTS 压测场景;
2、场景配置。PTS 反对对 MySQL、PostgreSQL 等四种数据库发动压测。用户填写 JDBC URL、用户名、明码和 SQL 即可发动压测。同时,PTS 还反对提取 ResultSet 中的数据作为出参,给上游 API 应用;对响应进行断言。
3、压测中监控和压测报告。PTS 反对绑定阿里云 RDS 云资源监控,在压测过程中察看 RDS 实时性能指标。此外,PTS 还提供清晰齐备的压测报告以及采样日志,供用户随时查看。
压测数据结构
背景
在模仿不同用户登录、压测业务参数传递等场景中,须要应用参数性能来实现压测的申请中各种动静操作。如果应用传统的 CSV 文件参数,会受到文件大小的限度,且手动创立消耗精力。应用 JDBC 来结构压测数据,能够防止以上问题。
步骤
1、增加数据源。在场景编辑 - 数据源治理中,抉择增加 DB 数据源,输出 URL、用户名、明码和 SQL。
2、增加参数。填写自定义参数名和列索引。
3、调试验证。点击调试场景,即可验证提取的后果集是否合乎预期。接着,咱们就能够在任意想要应用参数的
中央应用 ${}援用即可。
。