如何在jOOQ Active Record中延迟获取单个列
实现jOOQ单个bytea列的延迟加载
问题场景
我有一个PostgreSQL表,包含若干小型简单列和一个存储大型二进制数据的data列:
create table my_table ( id serial primary key, data bytea not null, description text );
通过jOOQ将该表的行读取到MyTableRecord中时,jOOQ会一次性获取所有列。虽然jOOQ支持fetchLazy()和stream()实现行级延迟获取,但这不适用于单个列。
生成的MyTableRecord类中,data列的getter方法直接返回内存中的数据:
... public byte[] getData() { return (byte[]) get(1); } ...
这意味着使用MyTableRecord的Active Record实例时,即使不需要data列,也必须从数据库获取全部数据。需要修改jOOQ/MyTableRecord的行为,使其仅在首次调用.getData()时才延迟获取data列,且不想通过拆分表建立1:1外键的方式解决。
解决方案:自定义Record实现列级延迟加载
1. 调整代码生成配置,排除data列的自动getter/setter
为了避免自动生成的getData()覆盖自定义逻辑,在jOOQ代码生成配置中排除data列的生成:
XML配置示例:
<generator> <database> <includes>my_table</includes> <excludes>my_table.data</excludes> </database> </generator>
Java配置示例:
new Generator() .withDatabase(new Database() .withIncludes("my_table") .withExcludes("my_table.data") );
2. 自定义Record子类,实现延迟加载逻辑
继承自动生成的MyTableRecord,实现自定义的getData()方法,加入延迟加载逻辑:
public class LazyMyTableRecord extends MyTableRecord { private byte[] data; private boolean dataLoaded = false; public LazyMyTableRecord() { super(); } // 从父类复制构造,保留已有列数据 public LazyMyTableRecord(MyTableRecord record) { super(record); } public byte[] getData() { if (!dataLoaded) { // 首次调用时,单独查询data列 data = DSL.using(getConfiguration()) .select(MY_TABLE.DATA) .from(MY_TABLE) .where(MY_TABLE.ID.eq(getId())) .fetchOne() .getValue(MY_TABLE.DATA); dataLoaded = true; } return data; } // 同步set方法,确保数据一致性 public void setData(byte[] data) { this.data = data; this.dataLoaded = true; super.setData(data); } }
3. 查询时返回自定义Record
查询时仅加载需要的小列,并用fetchInto()映射到自定义Record:
List<LazyMyTableRecord> records = DSL.using(configuration) .select(MY_TABLE.ID, MY_TABLE.DESCRIPTION) .from(MY_TABLE) .fetchInto(LazyMyTableRecord.class);
初始查询只会加载id和description,只有当调用getData()时,才会触发单独的数据库查询获取data列。
4. 线程安全优化(可选)
如果需要在多线程环境下使用,给getData()添加双重检查锁:
public byte[] getData() { if (!dataLoaded) { synchronized (this) { if (!dataLoaded) { data = DSL.using(getConfiguration()) .select(MY_TABLE.DATA) .from(MY_TABLE) .where(MY_TABLE.ID.eq(getId())) .fetchOne() .getValue(MY_TABLE.DATA); dataLoaded = true; } } } return data; }
内容的提问来源于stack exchange,提问作者Leprechaun
相关产品推荐
相关产品推荐

