在jOOQ中获取数据的多种不同方式
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中获取数据的多种不同方式相关推荐
- OC从plist文件中获取数据
怎样从plist文件中读取数据,这个和反归档相似,但是也存在着区别,比如说不用解码,当然一般我们获取的数据往往是对一个对象的描述,而且数据的个数也不是一个,因此我们有必要来说一下怎样完整的从plist ...
- C#从剪贴板中获取数据
今天我们同学问我如何利用C#把剪贴板里的图片存出来,我看了看,非常简单 IDataObject data = Clipboard.GetDataObject();//从剪贴板中获取数据 if(data ...
- c从sqlite3数据库中获取数据,并对数据进行拼接
c从sqlite3数据库中获取数据,并对数据进行拼接 函数功能 对数据库的操作 创建数据库: 创建USER表: 创建表内数据: 查看表内数据: 查看表结构: 函数实现 函数编译: 函数结果: 函数功能 ...
- 使用dom方式遍历文档||获取元素||从元素中获取数据
使用dom方式遍历文档 获取元素 根据id查询元素getElementById 根据标签获取元素getElementsByTag 根据class获取元素getElementsByClass 根据属性获 ...
- getdata提取曲线数据_Origin如何从图表中获取数据
点击上方"蓝字",一起愉快的玩耍吧!Origin如何从图表中获取数据01图片分析软件安装 一.GetData Graph Digitizer安装 使用范围: 1.需要引用别人文章中 ...
- Vue项目中获取数据后使用swiper轮播,无法轮播且 autoplay 和 loop 失效问题!
Vue项目中获取数据后使用swiper轮播,无法轮播且 autoplay 和 loop 失效问题! 问题表现:轮播组件显示第一张图,可拖动但无法切换到下一张图.但是F12控制台切换屏幕后能正常轮播但无 ...
- python临床数据_从临床试验中获取数据
我正在开发一个小Python函数来从clinicalTrials.gov中获取数据.从每个研究记录中,我想从中找出研究的目标条件.例如,对于this研究记录,我需要以下内容:conditions = ...
- 在React中获取数据
React初学者经常从不需要获取数据的应用开始.他们经常面临一个计数器,任务列表获取井字棋游戏应用.这是很好的,因为在开始学习React的时候,数据获取在你的应用中添加了另一层复杂度. 然而,有些时候 ...
- 如何在使用ASPMVC4的分部视图中获取数据展示
如何在使用ASPMVC4的分部视图中获取数据展示 在ASPMVC4中,创建的网站项目会用到分部视图,通过@Html.Partial("视图名")来加载到页面上: 但是如何把数据附加 ...
最新文章
- 一根棉签解决身上各种酸痛,立马感觉无比舒畅!
- 黑白青春-纪念那年我的秋天
- 云端迁移需谨遵四大关键步骤
- 高精度模板 c++/类封装
- Tomcat中两个不同项目共享Session
- 京东最新点击率预估模型论文学习和分享
- 浅谈程序员的职业规划
- C语言中188 10取模等于多少,C语言编程:任取x为十进制整数,编程将x转换成对应的八进制数后输出。...
- 英语总结系列(二十七):重复就是力量
- org.hibernate.hql.ast.QuerySyntaxException: myaddressbook is not mapped
- 从零开始,讲解详细,贴近实际应用,全面掌握用友ERP财务管理
- php 展示微信图片尺寸,微信公众平台图片最大尺寸
- 神奇的分形艺术: Mandelbrot集和Julia集
- 学习笔记(01):Java小白修炼手册-工欲善其事必先利其器,掌握Java开发工具
- 梦之光芒Monyer (全关解析)
- 郭敬明最经典的45句话
- 斗战神服务器正在维护6,斗战神什么时候服务器数据互通_斗战神1月6日、8日服务器数据互通公告_快吧游戏...
- Tomcat8启动不了的问题
- Windows 找不到网络 计算机或设备,“win7系统宽带拨号提示找不到设备”的解决方案...
- 下面是以十六进制格式存储的一个 UDP 首部:~~~TCP连接使用1000字节的窗口值,而上一次的确认号是22001~~那么下一个报文段的序号是否就是 x + 1 呢?在本题中列出的 8 种情况下,画
热门文章
- 招商直连系统,转账接口
- WinForm之中BindingNavigator控件的使用
- 辰视智能董事长冯良炳博士接受OFweek机器人网及工控网专访
- python 正则 匹配任意字符串_Python正则表达式匹配字符串中的任意纯数字
- 苹果 iOS 16.0.3 正式版发布:修复 iPhone 14 Pro / Max 通知延迟、相机启动慢等问题
- 酷我音乐盒html代码,享受音乐 酷我音乐盒独家秘籍偷偷报
- GreenPlum 大数据平台--介绍
- 指针——基础知识点归纳总结
- ios AVAssetExportSession的使用完整版
- 计算机专业数学差,数学差的同学适合学习计算机专业吗?