三、jOOQ系列教程查询结果处理

编程

jOOQ的代码生成器能够帮我们根据表结构生成对应的POJO,能很大程度上减少我们自己创建POJO的工作量,当然,此功能也是大部分ORM框架的必备功能。本章主要讲解各种方式将数据结果转换为我们想要的格式

Fetch 系列 API

查询操作通常以fetch API 作为结束API,例如常用的有,所有的读取类方法都差不多,掌握一个就能很快的举一反三

  • 读取多条

    • fetch 读取集合
    • fetchSet 读取并返回一个Set集合,常用于去重
    • fetchArray 读取并返回一个数组

  • 读取单条

    • fetchOne 读取单条记录,如果记录超过一条会报错
    • fetchAny 读取单条记录,如果有多条,会取第一条数据
    • fetchSingle 读取单条记录,如果记录为空或者记录超过一条会报错

  • 读取并返回Map

    • fetchMap 读取并返回一个Map
    • fetchGroups 读取并返回一个分组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

回到顶部