使用JOOQ转换器实现java.sql.Timestamp与java.time.Instant互转查询失效问题
问题原因
- 代码中存在多处语法和定义错误,导致绑定了转换器的自定义字段没有被正确识别:
- User类中
created字段定义时错误复用了name作为变量名,构造字段名时误用了不存在的table.getCreated()方法,同时重复调用了Converter.of()方法 - 插入语句指定的字段和实际传入的数值不匹配,代码中写的
User.firstName、User.lastName并没有提前定义
- User类中
- 核心的查询时转换器不生效问题,是因为你调用
select().from(User.table)时使用的是无参数的select(),相当于执行select *,jOOQ会返回无类型绑定的通用Record,默认使用JDBC原生的Timestamp类型,不会自动应用你自定义User.created字段绑定的转换器。
修复方案
- 先修正User类的字段定义:
public class User { private static final Converter<Timestamp, Instant> MY_CONVERTER= Converter.of( Timestamp.class, Instant.class, t -> t == null ? null : t.toInstant(), i -> i == null ? null : Timestamp.from(i) ); public static Table<?> table = DSL.table("user"); public static Field<String> name = DSL.field(DSL.name(table.getName(), "name"), String.class); // 修正变量名、字段构造参数、转换器绑定逻辑 public static Field<Instant> created = DSL.field(DSL.name(table.getName(), "created"), SQLDataType.TIMESTAMP.asConvertedDataType(MY_CONVERTER)); }
- 修正插入语句的字段参数,和传入值对应:
dslContext.insertInto(User.table, User.name, User.created) .values(user.getName(), user.getCreated()) .execute();
- 修正查询逻辑,触发转换器生效,两种方案可选:
- 方案一(推荐):查询时明确指定自定义的字段,返回的Record会自动应用转换器:
public Result<Record> getAll() { // 明确指定要查询的自定义字段,不要用无参数select() return dslContext.select(User.name, User.created).from(User.table).fetch(); }
修改后调用record.get(User.created)就会直接返回Instant类型,不需要额外转换。
- 方案二:如果确实需要查询全表所有字段,也可以在取值时显式指定转换器:
public static UserDto from(Record record) { UserDto user = new UserDto(); user.setName(record.get(User.name)); // 取值时显式传入转换器做转换 user.setCreated(record.get(User.created, MY_CONVERTER)); return user; }
内容的提问来源于stack exchange,提问作者ChambreNoire
相关产品推荐
相关产品推荐

