前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >5大隐藏的jOOQ功能

5大隐藏的jOOQ功能

作者头像
February
修改2018-11-26 15:17:39
2.5K0
修改2018-11-26 15:17:39
举报
文章被收录于专栏:技术翻译技术翻译

jOOQ的主要价值主张是显而易见的:Java中的类型安全的嵌入式SQL

当然,积极寻找这样一个SQL构建者的人将不可避免地偶然发现jOOQ并喜欢它。但是很多人并不真正需要SQL构建器 - 但是,jOOQ在其他情况下通过其鲜为人知的功能仍然非常有用。

这是前五个“隐藏”的jOOQ功能列表。

1.使用JDBC ResultSet

即使你不是直接使用jOOQ而是直接使用JDBC(或Spring JdbcTemplate等),最令人讨厌的事情之一就是使用ResultSet。JDBC ResultSet模拟数据库游标,它本质上是指向服务器上的集合的指针,可以定位在任何地方,即通过ResultSet.absolute(50)(记住从1开始计数)到第50个记录。

JDBC ResultSet针对延迟数据处理进行了优化。这意味着我们不必实现客户端中服务器生成的整个数据集。对于大型(甚至是大型)数据集来说,这是一个很好的功能,但在很多情况下,这是一个痛苦。当我们知道我们只获取十行并且我们知道我们在内存中将需要它们时,List<Record>类型会更方便。

jOOQ的org.jooq.Result 这样的List,幸运的是,您可以使用DSLContext.fetch(ResultSet)轻松导入任何JDBCResultSet

代码语言:javascript
复制
try (ResultSet rs = stmt.executeQuery()) {
    Result<Record> result = DSL.using(connection).fetch(rs);
    System.out.println(result);
}

考虑到这一点,您现在可以访问所有不错的jOOQ实用程序,例如格式化结果,即作为TEXT有关详细信息,请参阅第二个功能):

代码语言:javascript
复制
+---+---------+-----------+
| ID|AUTHOR_ID|TITLE      |
+---+---------+-----------+
|  1|        1|1984       |
|  2|        1|Animal Farm|
+---+---------+-----------+

当然,逆也是可能的。需要来自jOOQResult的JDBC ResultSet吗?调用Result.intoResultSet()并且您可以将伪结果注入到在JDBCResultSet上运行的任何应用程序:

代码语言:javascript
复制
DSLContext ctx = DSL.using(connection);
// Get ready for Java 10 with var!
var result = ctx.newResult(FIRST_NAME, LAST_NAME);
result.add(ctx.newRecord(FIRST_NAME, LAST_NAME)
              .values("John", "Doe"));
// Pretend this is a real ResultSet
try (ResultSet rs = result.intoResultSet()) {
  while (rs.next())
    System.out.println(rs.getString(1) + " " + rs.getString(2));
}

2.将结果导出为XML,CSV,JSON,HTML,TEXT或ASCII图表

正如我们在上一节中看到的,jOOQ Result类型具有很好的格式化功能。您也可以格式化为XMLCSVJSONHTMLTEXT,而不仅仅是文本。

格式通常可以根据您的需要进行调整。

例如,这种文本格式也是可能的:

代码语言:javascript
复制
ID AUTHOR_ID TITLE      
------------------------
 1         1 1984       
 2         1 Animal Farm   

格式化为CSV时,您将获得:

代码语言:javascript
复制
ID,AUTHOR_ID,TITLE
1,1,1984
2,1,Animal Farm

格式化为JSON时,您可能会得到:

代码语言:javascript
复制
[{"ID":1,"AUTHOR_ID":1,"TITLE":"1984"},
 {"ID":2,"AUTHOR_ID":1,"TITLE":"Animal Farm"}]

或者,根据您指定的格式选项,您可能更喜欢更紧凑的数组样式数组?

代码语言:javascript
复制
[[1,1,"1984"],[2,1,"Animal Farm"]]

或者XML,再次使用各种常见的格式样式,其中包括:

代码语言:javascript
复制
<result>
  <record>
    <ID>1</ID>
    <AUTHOR_ID>1</AUTHOR_ID>
    <TITLE>1984</TITLE>
  </record>
  <record>
    <ID>2</ID>
    <AUTHOR_ID>1</AUTHOR_ID>
    <TITLE>Animal Farm</TITLE>
  </record>
</result>

HTML似乎很明显。你会得到:

ID

AUTHOR_ID

TITLE

1

1

1984

2

1

Animal Farm

或者,在代码中:

代码语言:javascript
复制
<table>
<tr><th>ID</th><th>AUTHOR_ID</th><th>TITLE</th></tr>
<tr><td>1</td><td>1</td><td>1984</td></tr>
<tr><td>2</td><td>1</td><td>Animal Farm</td></tr>
</table>

作为奖励,您甚至可以将结果导出为ASCII图表:

这些功能是普通jOOQ查询的明显补充,但正如我在第1节中所示,您也可以从JDBC结果中获得免费导出!

3.再次导入这些文本格式

上一节的导出功能之后,考虑如何再次将这些数据导回到更有用的格式是很自然的。例如,当您编写集成测试时,您可能希望数据库查询返回如下结果:

代码语言:javascript
复制
ID AUTHOR_ID TITLE      
-- --------- -----------
 1         1 1984       
 2         1 Animal Farm  

只需将结果集的上述文本表示用Result.fetchFromTXT(String)导入到实际的jOOQ Result中,您就可以继续在jOOQ上运行Result(或者如第1节所示,使用JDBC ResultSet!)。

大多数其他导出格式(当然除了图表)也可以导入。

现在,你不希望Java有多行字符串(在这种情况下,这将非常好看):

代码语言:javascript
复制
Result<?> result = ctx.fetchFromTXT(
    "ID AUTHOR_ID TITLE      \n" +
    "-- --------- -----------\n" +
    " 1         1 1984       \n" +
    " 2         1 Animal Farm\n"
);
ResultSet rs = result.intoResultSet();

现在可以将这些类型注入到服务或DAO生成jOOQ Result或JDBCResultSet的任何位置。最明显的应用是嘲弄。第二个最明显的应用是测试。您可以轻松地测试服务是否产生上述表单的预期结果。

我们来谈谈mocking.......

4. Mocking JDBC

有时,mocking很酷。使用上述工具,jOOQ自然而然地提供了一个完整的,基于JDBC的模拟SPI。我在之前写过这个功能,并且在这里再一次提到了。

从本质上讲,您可以实现一个名为MockDataProviderFunctionalInterface。创建一个的最简单方法是使用方法,即:

代码语言:javascript
复制
MockDataProvider provider = Mock.of(ctx.fetchFromTXT(
    "ID AUTHOR_ID TITLE      \n" +
    "-- --------- -----------\n" +
    " 1         1 1984       \n" +
    " 2         1 Animal Farm\n"
));

此提供程序只是忽略所有输入(查询,绑定变量等),并始终返回相同的简单结果集。您现在可以将此提供程序插入MockConnection并使用它,就像任何普通的JDBC连接一样:

代码语言:javascript
复制
try (Connection c = new MockConnection(provider);
     PreparedStatement s = c.prepareStatement("SELECT foo");
     ResultSet rs = s.executeQuery()) {
    while (rs.next()) {
        System.out.println("ID        : " + rs.getInt(1));
        System.out.println("First name: " + rs.getString(2));
        System.out.println("Last name : " + rs.getString(3));
    }
}

输出是(完全忽略SELECT foo 语句):

代码语言:javascript
复制
ID        : 1
First name: 1
Last name : 1984
ID        : 2
First name: 1
Last name : Animal Farm

这个客户端代码甚至不使用jOOQ(虽然它可以)!这意味着您可以在任何基于JDBC的应用程序(包括基于Hibernate的应用程序)上使用jOOQ作为JDBC模拟框架。

当然,您并不总是希望返回完全相同的结果。这就是为什么MockDataProvider为您提供包含所有查询信息的参数:

代码语言:javascript
复制
try (Connection c = new MockConnection(ctx -> {
    if (ctx.sql().toLowerCase().startsWith("select")) {
        // ...
    }
})) {
    // Do stuff with this connection
}

您几乎可以使用单个lambda表达式实现整个JDBC驱动程序。在这里阅读更多。很酷,对吧?

旁注:不要误会我的意思:我认为你不应该因为可以而mock整个数据库层。我的想法可以在这个推特风暴中找到:

说到合成JDBC连接......

5.解析连接

jOOQ 3.9引入了一个SQL解析器,其主要用例是为代码生成器解析和反向工程DDL脚本

另一个尚未被讨论的功能(因为还有点实验)是解析连接,可通过DSLContext.parsingConnection()。同样,这是一个JDBC Connection实现,它包装物理JDBC连接,但在再次生成它们之前通过jOOQ解析器运行所有SQL查询。

重点是什么?

我们假设我们正在使用SQL Server,它支持以下SQL标准语法:

代码语言:javascript
复制
SELECT * FROM(VALUES(1),(2),(3))t(a)

结果是:

代码语言:javascript
复制
 a
---
 1
 2
 3 

现在,我们假设我们计划将应用程序迁移到Oracle。我们有以下不能在Oracle上运行的JDBC代码,因为Oracle不支持上述语法:

代码语言:javascript
复制
try (Connection c = DriverManager.getConnection("...");
     Statement s = c.createStatement();
     ResultSet rs = s.executeQuery(
         "SELECT * FROM (VALUES (1), (2), (3)) t(a)")) {
    while (rs.next())
        System.out.println(rs.getInt(1));
}

现在,我们有三个选项(提示#1很糟糕;#2和#3很酷):

  1. 繁琐地将所有这样的手动编写的基于JDBC的SQL迁移到Oracle语法,并希望我们不必再次迁移回来。
  2. 升级我们基于JDBC的应用程序以使用jOOQ(当然,这是最好的选择,但它也需要一些时间)。
  3. 只需使用如下所示的jOOQ解析连接,即可开箱即用很多代码!(然后,当然,逐渐迁移到jOOQ - 参见选项#2。)
代码语言:javascript
复制
try (DSLContext ctx = DSL.using("...");
     Connection c = ctx.parsingConnection(); // Magic here
     Statement s = c.createStatement();
     ResultSet rs = s.executeQuery(
         "SELECT * FROM (VALUES (1), (2), (3)) t(a)")) {
    while (rs.next())
        System.out.println(rs.getInt(1));
}

我们没有触及任何基于JDBC的客户端逻辑。我们只介绍了一个代理JDBC连接,它在重新生成包装的物理JDBC连接上的语句之前通过jOOQ解析器运行每个语句。

在Oracle上真正执行的是这里的仿真:

代码语言:javascript
复制
select t.a from (
  (select null a from dual where 1 = 0) union all 
  (select * from (
    (select 1 from dual) union all 
    (select 2 from dual) union all 
    (select 3 from dual)
  ) t)
) t

看起来很棒,是吗?此处描述了此仿真的基本原理

jOOQ可以使用其API表示的每个SQL功能以及它可以在数据库之间进行模拟的功能都将受到支持!这包括更多琐碎的事情,比如解析这个查询:

代码语言:javascript
复制
SELECT substring('abcdefg', 2, 4)

...而在Oracle上运行这个:

代码语言:javascript
复制
select substr('abcdefg', 2, 4) from dual

你们都在想:

结论

jOOQ API中有许多这样的好东西可以帮助您提高效率。

原文标题《Top 5 Hidden jOOQ Features》

作者:Lukas Eder

译者:February

不代表云加社区观点,更多详情请查看原文链接

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系外文翻译前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.使用JDBC ResultSet
  • 2.将结果导出为XML,CSV,JSON,HTML,TEXT或ASCII图表
  • 3.再次导入这些文本格式
  • 4. Mocking JDBC
  • 5.解析连接
  • 结论
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档