三、jOOQ系列教程查询结果处理
jOOQ的代码生成器能够帮我们根据表结构生成对应的POJO,能很大程度上减少我们自己创建POJO的工作量,当然,此功能也是大部分ORM框架的必备功能。本章主要讲解各种方式将数据结果转换为我们想要的格式
Fetch 系列 API
查询操作通常以fetch API 作为结束API,例如常用的有,所有的读取类方法都差不多,掌握一个就能很快的举一反三
- 读取多条
fetch
读取集合fetchSet
读取并返回一个Set集合,常用于去重fetchArray
读取并返回一个数组
- 读取单条
fetchOne
读取单条记录,如果记录超过一条会报错fetchAny
读取单条记录,如果有多条,会取第一条数据fetchSingle
读取单条记录,如果记录为空或者记录超过一条会报错
- 读取并返回Map
fetchMap
读取并返回一个MapfetchGroups
读取并返回一个分组Map
fetch
作为一个常用的读取多条记录的API,其他几个读取多条的方法和这个方法类似,只是返回值不同
fetchSet, fetchArray
方法和 fetch
方法一样,都是返回多条数据,只是返回的格式不同,fetch通常返回List或者jOOQ的Result对象
接下来介绍一下几个方法重载的返回值
fetch()
无参调用此方法,返回的是一个
Result<Record>
结果集对象
Result<Record> records = dslContext.select().from(S1_USER).fetch();
fetch(RecordMapper mapper)
RecordMapper
接口的提供map
方法,用于来返回数据。map
方法传入一个Record
对象。可以使用lambda表达式将Record
对象转换成一个指定类型的POJO
List<S1UserPojo> userPojoList = dslContext.select() .from(S1_USER)
.where(S1_USER.ID.eq(1))
.fetch(r -> r.into(S1UserPojo.class));
多表查询,字段相同时,直接用into方法将结果集转换为POJO时,相同字段名称的方法会以最后一个字段值为准。这时候,我们可以现将结果集通过 `into(Table table)` 方法将结果集转换为指定表的`Record`对象,然后再`into`进指定的POJO类中
// 多表关联查询,查询s2_user_message.id = 2的数据,直接into的结果getId()却是1// 这是因为同时关联查询了s1_user表,该表的id字段值为1
List<S2UserMessage> userMessage = dslContext.select().from(S2_USER_MESSAGE)
.leftJoin(S1_USER).on(S1_USER.ID.eq(S2_USER_MESSAGE.USER_ID))
.where(S2_USER_MESSAGE.ID.eq(2))
.fetch(r -> r.into(S2UserMessage.class));
// userMessage.getId() == 1
// 将结果集into进指定的表描述中,然后在into至指定的POJO类
List<S2UserMessage> userMessage2 = dslContext.select().from(S2_USER_MESSAGE)
.leftJoin(S1_USER).on(S1_USER.ID.eq(S2_USER_MESSAGE.USER_ID))
.where(S2_USER_MESSAGE.ID.eq(2))
.fetch(r -> {
S2UserMessage fetchUserMessage = r.into(S2_USER_MESSAGE).into(S2UserMessage.class);
fetchUserMessage.setUsername(r.get(S1_USER.USERNAME));
return fetchUserMessage;
});
// userMessage.getId() == 2
fetch(Field<?> field)
Field
是一个接口,代码生成器生成的表字段常量例如S1_USER.ID
, 都实现了Field
接口,这个重载可以直接取出指定表字段,会自动根据传入的字段推测其类型
List<Integer> id = dslContext.select().from(S1_USER).where(S1_USER.ID.eq(1)) .fetch(S1_USER.ID);
fetch(String fieldName, Class<?> type)
可以直接通过字段名称字符串获取指定字段值,可以通过第二个参数指定返回值,如果不指定,返回Object
List<Integer> idList = dslContext.select().from(S1_USER).where(S1_USER.ID.eq(1)) .fetch("id", Integer.class);
fetch(int fieldIndex, Class<?> type)
可以通过查询字段下标顺序进行查询指定字段,可以通过第二个参数指定返回值,如果不指定,返回Object
List<Integer> idList = dslContext.select(S1_USER.ID, S1_USER.USERNAME) .from(S1_USER).where(S1_USER.ID.eq(1)).fetch(0, Integer.class);
fetch*
fetchSet, fetchArray, fetchAny, fetchOne, fetchSingle
这几个方法的和 fetch
方法的用法一致,只是返回值不同,这里不做详解
fetchAny, fetchOne, fetchSingle
方法返回单条数据,但是对于 数据为空、SQL结果为多条数据 的情况下,处理方式各不相同
方法名 无数据 多条数据 单条数据
fetchAny
返回空
返回第一条
正常返回
fetchOne
返回空
抛出异常
正常返回
fetchSingle
抛出异常
抛出异常
正常返回
org.jooq.exception.TooManyRowsException
多条数据时抛出异常org.jooq.exception.NoDataFoundException
无数据时抛出异常
fetchMap
此方法可以将结果集处理为一个Map格式,此方法有很多重载,这里介绍几个常用的,注意,此方法作为key的字段必须确定是在当前结果集中是唯一的,如果出现重复key,此方法会抛出异常
fetchMap(Field<K> field, Class<V> type)
以表字段值为key,返回一个
K:V
的Map对象
Map<Integer, S1UserPojo> idUserPojoMap = dslContext.select().from(S1_USER) .fetchMap(S1_USER.ID, S1UserPojo.class);
fetchMap(Feild<K> field, Field<V> field)
以表字段值为key,返回一个
K:V
的Map对象
Map<Integer, String> idUserNameMap = dslContext.select().from(S1_USER) .fetchMap(S1_USER.ID, S1_USER.USERNAME);
fetchGroups
此方法可以将结果集处理为一个Map格式,和fetchMap
类似,只不过这里的值为一个指定类型的集合,通常在处理一对多数据时会用到
fetchGroups(Field<K> field, Class<V> type)
以表字段值为Key,返回一个
K:List<V>
的Map对象
Map<Integer, List<S2UserMessage>> userIdUserMessageMap = dslContext.select().from(S2_USER_MESSAGE) .fetchGroups(S2_USER_MESSAGE.USER_ID, S2UserMessage.class);
fetchGroups(Field<K> keyField, Field<V> valueField)
- 以表字段值为Key,返回一个
K:List<V>
的Map对象
Map<Integer, List<Integer>> userIdUserMessageIdMap = dslContext.select().from(S2_USER_MESSAGE) .fetchGroups(S2_USER_MESSAGE.USER_ID, S2_USER_MESSAGE.ID);
内容总结
本章源码: https://github.com/k55k32/learn-jooq/tree/master/section-3
文章主要讲解的是各种类型的读取API,掌握好这些API对于jOOQ的使用很有帮助
本章中出现的一下几个接口可能是在编码过程中经常遇到的
Field<T>
接口由代码生成器生成的所有表字段常量,都是此接口的实现类,包含了字段一些基本信息,例如字段名称,字段数据类型等,所有读取类方法都有基于此字段参数的重载
RecordMapper<? super R, E> mapper
接口该接口很简单,主要是提供一个
map
方法给大家去实现。此接口只有一个方法,可以通过lambda表达式快速实现该接口。所有读取类方法都有基于此接口参数的重载
public interface RecordMapper<R extends Record, E> { E map(R record);
}
以上是 三、jOOQ系列教程查询结果处理 的全部内容, 来源链接: utcz.com/z/513526.html