jOOQ的API是关于方便的,因此,像 fetch() 这样的重要操作(最重要的操作?)也必须附带方便。获取数据的默认方式是这样的:

Result<Record1<String>> result =
ctx.select(BOOK.TITLE).from(BOOK).fetch();for (Record1<String> record : result) {// ...
}
复制代码

它将整个结果集取到内存中,并急切地关闭底层的JDBC资源。但是我们还有什么其他的选择呢?

可迭代的获取方式

在上面的例子中, fetch() 的调用并不是严格意义上的必要。 [ResultQuery<R>](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/ResultQuery.html) 类型 方便地扩展了 Iterable<R> , 这意味着对 ResultQuery.iterator() 的调用也将执行该查询。这主要可以通过两种方式实现。

外部迭代

for (Record1<String> record : ctx.select(BOOK.TITLE).from(BOOK)
) {// ...
}
复制代码

这特别好,因为它感觉就像PL/SQL或PL/pgSQL的 FOR 循环,用于隐式游标:

FOR rec IN (SELECT book.title FROM book) LOOP-- ...
END LOOP;
复制代码

不过这仍然要把整个结果集取到内存中,因为在Java中没有一个 for-with-resources 语法,它把 foreach 语法和 try-with-resources 语法结合起来。

内部迭代

JDK 8增加了 Iterable::forEach ,jOOQ的 [ResultQuery](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/ResultQuery.html) 继承了,所以你也可以这样做。

ctx.select(BOOK.TITLE).from(BOOK).forEach(record -> {// ...});
复制代码

两者是完全等价的。

单一记录的获取

如果你确定你只取一个单一的值,不需要具体化一个列表。只需使用以下方法之一。鉴于这个查询:

ResultQuery<Record1<String>> query = ctx.select(BOOK.TITLE).from(BOOK).where(BOOK.ID.eq(1));
复制代码

你现在可以

取一个可空的记录

这就获取了一个可空的记录,也就是说,如果没有找到记录,就会产生 null 。如果有一条以上的记录,就会产生一个 [TooManyRowsException](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/exception/TooManyRowsException.html) 会被抛出。

Record1<String> r = query.fetchOne();
复制代码

取一个可选择的记录

null 自行车棚是真实的,那么为什么在使用jOOQ的时候不让你也骑自行车呢?与上述完全等同,但使用不同的风格,是这样的。

Optional<Record1<String>> r = query.fetchOptional();
复制代码

取出一条记录

如果你知道你的查询正好产生一条记录,在jOOQ的API中有一个术语 "single",意思是正好一条:

Record1<String> r = query.fetchSingle();
println(r.toString()); // NPE safe!
复制代码

r.toString() NullPointerException 的调用是安全的,因为如果记录不存在,a [NoDataFoundException](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/exception/NoDataFoundException.html) 会被抛出。

资源性获取

默认情况下是急切地把所有东西都取到内存中,因为这可能比JDBC默认的一直管理资源(包括嵌套集合、lobs等)对大多数应用更有用。从上面的 Iterator fetching例子中可以看出,考虑到用户甚至不能通过jOOQ访问资源(默认情况下),这往往是唯一可能不产生意外资源泄露的方法。

但这并不 总是 正确的选择,所以如果你的数据集很大的话,你可以在获取数据的同时保持开放底层JDBC资源。有2种主要方式。

强制性的

通过调用 [ResultQuery.fetchLazy()](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/ResultQuery.html#fetchLazy()) ,你就创建了一个 [Cursor<R>](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/Cursor.html) ,它包装了底层的JDBC ResultSet ,因此,应该包含在一个 try-with-resources 语句中。

try (Cursor<Record1<String>> cursor = ctx.select(BOOK.TITLE).from(BOOK).fetchLazy()
) {for (Record1<String> record : cursor) {// ...}
}复制代码

Cursor<R> 仍然扩展了 Iterable<R> ,但你也可以从它那里手动获取记录,例如:

Record record;while ((record = cursor.fetchNext()) != null) {// ...
}复制代码

功能性的

如果 Stream API更像你想处理的数据,只要调用 [ResultQuery.fetchStream()](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/ResultQuery.html#fetchStream()) 来代替,那么(但别忘了也要用 try-with-resources 来包装!):

try (Stream<Record1<String>> stream = ctx.select(BOOK.TITLE).from(BOOK).fetchStream()
) {stream.forEach(record -> {// ...});
}复制代码

或者,使用 Stream::map 、 Stream::reduce ,或者其他什么。遗憾的是, Stream API并不是自动关闭的。虽然这样实现API是可能的,但它的 "逃生舱",如 Stream.iterator() ,仍然会阻止自动关闭的行为(至少,除非有更多的功能被引入,如 AutoCloseableIterator ,或其他什么)。

所以,你必须用 try-with-resources 语句打破你的流畅管道。

功能性的,但不是资源性的

当然,你总是可以先调用 fetch() ,然后再调用stream,以便直接从你的内存中流转数据。如果资源性并不重要(即对性能的影响可以忽略不计,因为结果集并不大),你可以这样写:

ctx.select(BOOK.TITLE).from(BOOK).fetch().stream().forEach(record -> {// ...});复制代码

或者使用 Stream::map , Stream::reduce , 或其他什么方式

采集器获取

从jOOQ 3.11版本开始,无论是 [ResultQuery::collect](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/ResultQuery.html#collect(java.util.stream.Collector)) 和 [Cursor::collect](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/Cursor.html#collect(java.util.stream.Collector)) 已经被添加进来了。JDK Collector API是非常强大的。它并没有得到应有的关注(在 Stream API之外)。在我看来,应该有一个 Iterable::collect 方法,因为在任何集合上重新使用 Collector 类型是有意义的,例如:

Set<String> s = Set.of(1, 2, 3);
List<String> l = s.collect(Collectors.toList());
复制代码

为什么不呢? Collector 有点像 Stream API本身的对偶。这些操作不是以流水线的语法组成的,而是以嵌套的语法组成的。除此以外,至少对我来说,它感觉非常相似。

就jOOQ而言,它们非常强大。jOOQ提供了一些有用的开箱即用的收集器,在 [Records](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/Records.html) .让我展示一下 [Records.intoMap()](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/Records.html#intoMap()) 的例子,它有这个重载:

<K,V,R extends Record2<K,V>> Collector<R,?,Map<K,V>> intoMap()
复制代码

这里有趣的一点是,它捕获了一个 Record2 类型的类型,作为结果映射的键和值类型。一个简单的通用技巧,以确保它只在你正好投射2列的情况下工作,比如说:

Map<Integer, String> books =
ctx.select(BOOK.ID, BOOK.TITLE).from(BOOK).collect(Records.intoMap());
复制代码

这完全是类型安全的。你不能投射3列,或者由于所有这些泛型而投射错误的列类型。这比直接在 ResultQuery API上提供的等价物更方便,在那里你必须重复投影列的表达式:

Map<Integer, String> books =
ctx.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchMap(BOOK.ID, BOOK.TITLE);
复制代码

通过 ResultQuery::collect 和 Cursor::collect API,你可以使用任何任意的收集器,包括你自己的收集器,这真的是非常强大的!这也是为什么你可以使用 。另外,它还消除了对中间的 Result 数据结构的需要,所以它不必把所有的东西都取到内存中(当然,除非你的 Collector 反正是这样做)。

收集器在收集 MULTISET 嵌套集合时特别有用。这里已经给出了一个例子, 一个嵌套的集合也被映射到这样的 Map<K, V> 。

反应式获取

从jOOQ 3.15开始,R2DBC得到了支持 。这意味着 [ResultQuery<R>](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/ResultQuery.html) 现在也是一个反应式流 Publisher<R> (同时支持 reactive-streams API和JDK 9 Flow API,以提高互操作性)。

所以,只要选择你最喜欢的反应式流API,比如reactor,然后像这样反应式地流取jOOQ的结果集:

Flux<Record1<String>> flux = Flux.from(ctx.select(BOOK.TITLE).from(BOOK)
);
复制代码

许多获取

最后但并非最不重要的是,在极少数情况下,你的查询会产生一个以上的结果集。这在SQL Server和相关的RDBMS中曾经很流行,存储过程可以产生游标。MySQL和Oracle也有这个功能。比如说:

Results results = ctx.fetch("sp_help");for (Result<?> result : results) {for (Record record : result) {// ...}
}
复制代码

标准的 foreach 循环只会迭代结果,但你也可以使用下面的方法访问交错的行数 [Results.resultsOrRows()](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/Results.html#resultsOrRows()) 如果你对这个也感兴趣的话。

总结

方便和开发者的用户体验是jOOQ的API设计的核心。像任何好的集合API一样,jOOQ提供了各种可组合的基元,允许更有效地将SQL整合到你的应用程序中。

SQL只是对数据结构的描述。jOOQ帮助在JVM上以一种类型安全的方式描述该数据结构。以同样类型安全的方式进行进一步处理是很自然的,就像我们习惯于从JDK自己的集合API或第三方(如 jOOλ 、 vavr 、 streamex 等)获得的那样。

在jOOQ中获取数据的多种不同方式相关推荐

  1. OC从plist文件中获取数据

    怎样从plist文件中读取数据,这个和反归档相似,但是也存在着区别,比如说不用解码,当然一般我们获取的数据往往是对一个对象的描述,而且数据的个数也不是一个,因此我们有必要来说一下怎样完整的从plist ...

  2. C#从剪贴板中获取数据

    今天我们同学问我如何利用C#把剪贴板里的图片存出来,我看了看,非常简单 IDataObject data = Clipboard.GetDataObject();//从剪贴板中获取数据 if(data ...

  3. c从sqlite3数据库中获取数据,并对数据进行拼接

    c从sqlite3数据库中获取数据,并对数据进行拼接 函数功能 对数据库的操作 创建数据库: 创建USER表: 创建表内数据: 查看表内数据: 查看表结构: 函数实现 函数编译: 函数结果: 函数功能 ...

  4. ​​​​​​​​​​​​​​使用dom方式遍历文档||获取元素||从元素中获取数据

    使用dom方式遍历文档 获取元素 根据id查询元素getElementById 根据标签获取元素getElementsByTag 根据class获取元素getElementsByClass 根据属性获 ...

  5. getdata提取曲线数据_Origin如何从图表中获取数据

    点击上方"蓝字",一起愉快的玩耍吧!Origin如何从图表中获取数据01图片分析软件安装 一.GetData Graph Digitizer安装 使用范围: 1.需要引用别人文章中 ...

  6. Vue项目中获取数据后使用swiper轮播,无法轮播且 autoplay 和 loop 失效问题!

    Vue项目中获取数据后使用swiper轮播,无法轮播且 autoplay 和 loop 失效问题! 问题表现:轮播组件显示第一张图,可拖动但无法切换到下一张图.但是F12控制台切换屏幕后能正常轮播但无 ...

  7. python临床数据_从临床试验中获取数据

    我正在开发一个小Python函数来从clinicalTrials.gov中获取数据.从每个研究记录中,我想从中找出研究的目标条件.例如,对于this研究记录,我需要以下内容:conditions = ...

  8. 在React中获取数据

    React初学者经常从不需要获取数据的应用开始.他们经常面临一个计数器,任务列表获取井字棋游戏应用.这是很好的,因为在开始学习React的时候,数据获取在你的应用中添加了另一层复杂度. 然而,有些时候 ...

  9. 如何在使用ASPMVC4的分部视图中获取数据展示

    如何在使用ASPMVC4的分部视图中获取数据展示 在ASPMVC4中,创建的网站项目会用到分部视图,通过@Html.Partial("视图名")来加载到页面上: 但是如何把数据附加 ...

最新文章

  1. 一根棉签解决身上各种酸痛,立马感觉无比舒畅!
  2. 黑白青春-纪念那年我的秋天
  3. 云端迁移需谨遵四大关键步骤
  4. 高精度模板 c++/类封装
  5. Tomcat中两个不同项目共享Session
  6. 京东最新点击率预估模型论文学习和分享
  7. 浅谈程序员的职业规划
  8. C语言中188 10取模等于多少,C语言编程:任取x为十进制整数,编程将x转换成对应的八进制数后输出。...
  9. 英语总结系列(二十七):重复就是力量
  10. org.hibernate.hql.ast.QuerySyntaxException: myaddressbook is not mapped
  11. 从零开始,讲解详细,贴近实际应用,全面掌握用友ERP财务管理
  12. php 展示微信图片尺寸,微信公众平台图片最大尺寸
  13. 神奇的分形艺术: Mandelbrot集和Julia集
  14. 学习笔记(01):Java小白修炼手册-工欲善其事必先利其器,掌握Java开发工具
  15. 梦之光芒Monyer (全关解析)
  16. 郭敬明最经典的45句话
  17. 斗战神服务器正在维护6,斗战神什么时候服务器数据互通_斗战神1月6日、8日服务器数据互通公告_快吧游戏...
  18. Tomcat8启动不了的问题
  19. Windows 找不到网络 计算机或设备,“win7系统宽带拨号提示找不到设备”的解决方案...
  20. 下面是以十六进制格式存储的一个 UDP 首部:~~~TCP连接使用1000字节的窗口值,而上一次的确认号是22001~~那么下一个报文段的序号是否就是 x + 1 呢?在本题中列出的 8 种情况下,画

热门文章

  1. 招商直连系统,转账接口
  2. WinForm之中BindingNavigator控件的使用
  3. 辰视智能董事长冯良炳博士接受OFweek机器人网及工控网专访
  4. python 正则 匹配任意字符串_Python正则表达式匹配字符串中的任意纯数字
  5. 苹果 iOS 16.0.3 正式版发布:修复 iPhone 14 Pro / Max 通知延迟、相机启动慢等问题
  6. 酷我音乐盒html代码,享受音乐 酷我音乐盒独家秘籍偷偷报
  7. GreenPlum 大数据平台--介绍
  8. 指针——基础知识点归纳总结
  9. ios AVAssetExportSession的使用完整版
  10. 计算机专业数学差,数学差的同学适合学习计算机专业吗?