ITPub博客

首页 > 数据库 > 数据库开发技术 > DevX 开源组件 DevXRoutingDataSource SQL 解析测试篇

DevX 开源组件 DevXRoutingDataSource SQL 解析测试篇

原创 数据库开发技术 作者:DevXTalk 时间:2023-05-31 22:17:19 0 删除 编辑

DevX 开源组件 DevXRoutingDataSource SQL 解析测试篇

DevXRoutingDataSource 的核心功能也是最基础的理念是根据 SQL 语句去进行多数据源的路由, 所以 SQL 解析是其中很重要的一个环节。为了保障开源项目的质量,我们会编写很多的测试代码,从各个角度对代码进行测试。本章内容是关于对 SQL 解析进行测试。

SQL 解析实现

目前提供了两种实现,一种基于 Apache Calcite (https://github.com/apache/calcite) (开发中) , 一种基于 JSqlParser (https://github.com/JSQLParser/JSqlParser)

JSqlParser 基于 Visitor 设计模式编写. Visitor 设计模式是一种行为型设计模式,它允许你将算法与其所作用的对象分离开来。通过这种方式,你可以在不修改对象结构的情况下向现有对象结构添加新的操作。它的主要思想是将操作(也称为 Visitor)与元素(也称为 Visitable)分离开来。Visitor 通过访问元素并执行操作来实现其目的。这种模式通常用于对象结构包含多种类型的对象,而你希望对这些对象进行一些共同的操作,同时又不希望将这些操作添加到对象本身中。

下面是关于如何使用 JSqlParser 的简单示例.

Parse the SQL Text into Java Objects:

String sqlStr="select 1 from dual where a=b";

Statement statement = CCJSqlParserUtil.parse(sqlStr);
if (statement instanceof Select) {
Select select = (Select) statement;
PlainSelect plainSelect = (PlainSelect) select.getSelectBody();

SelectExpressionItem selectExpressionItem = (SelectExpressionItem) plainSelect.getSelectItems().get(0);
Assertions.assertEquals( new LongValue(1), selectExpressionItem.getExpression());

Table table = (Table) plainSelect.getFromItem();
Assertions.assertEquals("dual", table.getName());

EqualsTo equalsTo = (EqualsTo) plainSelect.getWhere();
Column a = (Column) equalsTo.getLeftExpression();
Column b = (Column) equalsTo.getRightExpression();
Assertions.assertEquals("a", a.getColumnName());
Assertions.assertEquals("b", b.getColumnName());
}

Traverse the Java Object Tree using the Visitor Patterns:

// Define an Expression Visitor reacting on any Expression
// Overwrite the visit() methods for each Expression Class
ExpressionVisitorAdapter expressionVisitorAdapter = new ExpressionVisitorAdapter() {
public void visit(EqualsTo equalsTo) {
equalsTo.getLeftExpression().accept(this);
equalsTo.getRightExpression().accept(this);
}
public void visit(Column column) {
System.out.println("Found a Column " + column.getColumnName());
}
};

// Define a Select Visitor reacting on a Plain Select invoking the Expression Visitor on the Where Clause
SelectVisitorAdapter selectVisitorAdapter = new SelectVisitorAdapter() {
@Override
public void visit(PlainSelect plainSelect) {
plainSelect.getWhere().accept(expressionVisitorAdapter);
}
};

// Define a Statement Visitor for dispatching the Statements
StatementVisitorAdapter statementVisitor = new StatementVisitorAdapter() {
public void visit(Select select) {
select.getSelectBody().accept(selectVisitorAdapter);
}
};

String sqlStr="select 1 from dual where a=b";
Statement stmt = CCJSqlParserUtil.parse(sqlStr);

// Invoke the Statement Visitor
stmt.accept(statementVisitor);

Unit Test 单元测试

单元测试的重点是针对功能进行测试,验证行为的正确性. 这里使用 junit5 进行单元测试 , 使用 assertj 进行测试后的断言.

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.3</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.3</version>
<scope>test</scope>
</dependency>


<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.23.1</version>
<scope>test</scope>
</dependency>

针对各种语法的 SQL 进行单元测试, 大致的涵盖范围是 SELECT , INSERT , UPDATE , DELETE . 还包括 JOIN 子句 , Sub Query 子句等. 但是依然不敢保证以及涵盖了所有的标准语法情况,之后会补充完善.

Benchmark Test 基础测试

为了保障开源项目的质量,在保障正确性的基础上还需要对性能提供保障. 所以进行了 Benchmark Test 来发现代码中潜在存在的问题.

Benchmark Test(基准测试)是一种常用于评估计算机性能和稳定性的测试方法。Benchmark Test 通过运行一组标准化测试来模拟计算机在不同负载下的性能表现,可以测量各种硬件和软件组件(如 CPU、内存、磁盘、网络等)的性能指标。

通常,Benchmark Test 由一些常见的、严谨的、可以重复的测试用例组成,这些用例反映了计算机在典型工作负载下的性能表现。测试过程会记录数据,如启动时间、读取和写入速度、响应时间等,并将这些数据与其他系统进行对比,以确定计算机在相应方面的表现。结果可能会绘制成图表以便直观展示。

使用 Benchmark Test 可以帮助用户评估计算机硬件和软件的性能,了解它们在处理某些任务时的表现,并帮助选择合适的设备或软件。同时,Benchmark Test 也有助于开发人员测试和优化代码,提高应用程序的性能。

需要注意的是,Benchmark Test 只是评估计算机在特定负载下的性能,因此在实际应用中,可能会因为其他因素而导致表现不同。因此,在进行 Benchmark Test 时,需要注意测试环境的设置、测试用例的选择、数据的准确性等,以确保测试结果的可靠性和有效性。

在进行 Benchmark Test 时使用了 Java Microbenchmark Harness (JMH) . 为了编写的单元测试代码可以重复使用的目的,采用了 junit5 和 JMH 测试方法结合的方式.

<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.36</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.36</version>
<scope>test</scope>
</dependency>

在单元测试类中提供了一个 testBenchmark 方法, 在该方法内进行 JMH 的基本配置.

在每个单元测试方法上加上 JMH 注解,用来规定 JMH 对该方法的测试细节.

@Benchmark
@Warmup(iterations = 5, time = 5, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 200, time = 5, timeUnit = TimeUnit.MILLISECONDS)
@CompilerControl(CompilerControl.Mode.INLINE)
@OutputTimeUnit(TimeUnit.MILLISECONDS)

在运行 Benchmark Test 完成后, 会在项目根路径下得到 jmh-result.json 和 JSqlParser_Benchmark.json 两个测试结果文件, 这里我指定 JSON 格式输出, 还支持 TEST , CSV , SCSV , LATEX 格式文件.

jmh-result.json 文件记录了对每一个方法测试的参数和结果

JSqlParser_Benchmark.json 文件记录了对每一个方法测试的参数和结果

直接看这两个文件可能不是太友好,推荐两个个可视化工具可以将测试结果文件以图标的形式展示.

  • http://deepoove.com/jmh-visual-chart/
  • https://jmh.morethan.io/
平均时间
采样时间
单次操作时间
吞吐量

我们的单元测试遵循规范,无需依赖任何外部引入,在任何地方任何时候都可以重复执行.


每日英语学习

What's up buddy?
You made it.
Another day, one more done.
You should be proud of yourself.
You really should.
I'm proud of you.
I konw you got a lot going on.
I know you got a lot of shit on your shoulders.
You got a lot of shit on your chest.
Don't stop. You can't quit now.
You come too far man.
Your heart's a warrior.
You're stronger than you think.
You made it through all them other bad days,and I know these days they all blend together.
Yesterday feels like today, and tomorrow's gonna feel like yesterday.
It's kind a just the way it goes, there's only one thing you can do,you gotta change tomorrow , you gotta be better than you were today.
Don't forget, your future you needs you,your past you doesn't,you'll be alright, i know you will, you always are.
Make sure you come back.


DevX 会持续分享有趣的技术和见闻,如果你觉得本文对你有帮助希望你可以分享给更多的朋友看到。该文章会同步在微信公众号 【DevXJava】, 方便在微信客户端阅读。

DevX 不止于技术

原文作者:DevXTalk;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2019-03-23

  • 博文量
    178
  • 访问量
    82582