乐趣区

关于阿里云:JDBC-在性能测试中的应用

作者:黄炎帝

前言

咱们是否绕开 http 协定,间接测试数据库的性能?是否感觉从数据库中导出 CSV 文件来结构压测数据很麻烦?怎么在压测完结后做数据清理?能不能通过数据库中的插入(删除)记录对压测申请做断言?应用阿里云性能测试工具 PTS 能够轻松解决上述问题。

什么是 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、调试验证。点击调试场景,即可验证提取的后果集是否合乎预期。接着,咱们就能够在任意想要应用参数的
中央应用 ${}援用即可。

压测脏数据清理

  • 背景

针对写申请的压测,会在数据库中生成大量脏数据。如何在压测完结后主动清理?

  • 步骤

PTS 给用户提供了解决方案。PTS 反对对串联链路作逻辑上的程序编排,即前置链路、一般链路和后置链路。执行程序由先到后。设置某条串联链路为后置链路,填写循环次数即可。

更多交换,欢送进钉钉群沟通,PTS 用户交换钉钉群号:11774967。

此外,PTS 近期对售卖形式做了全新降级,根底版价格直降 50%!5W 并发价格只需 199,免去自运维压测平台懊恼!更有新用户 0.99 体验版、VPC 压测专属版,欢送大家选购!

退出移动版