如何用jOOQ从DuckDB中获取WKB(Blob类型)字段?
解决jOOQ读取DuckDB中WKB几何列的BufferUnderflowException问题
自定义jOOQ绑定处理WKB列
DuckDB JDBC驱动读取Blob时抛出的BufferUnderflowException,大概率是驱动对Blob的实现不符合JDBC标准导致的。可以通过自定义jOOQ绑定绕开默认Blob处理逻辑,直接读取原始字节:
import org.jooq.*; import org.jooq.impl.AbstractBinding; import java.sql.*; public class WkbBinding extends AbstractBinding<byte[], byte[]> { @Override public Converter<byte[], byte[]> converter() { return Converters.identityConverter(); } @Override public void set(BindingSetStatementContext<byte[]> ctx) throws SQLException { ctx.statement().setBytes(ctx.index(), ctx.value()); } @Override public void get(BindingGetResultSetContext<byte[]> ctx) throws SQLException { byte[] bytes = ctx.resultSet().getBytes(ctx.index()); ctx.value(bytes); } @Override public void get(BindingGetStatementContext<byte[]> ctx) throws SQLException { byte[] bytes = ctx.statement().getBytes(ctx.index()); ctx.value(bytes); } }
在jOOQ代码生成配置中,指定该绑定到所有WKB几何列:
<forcedTypes> <forcedType> <userType>byte[]</userType> <binding>com.yourpackage.WkbBinding</binding> <includeExpression>LOCATION\.GEOM|.*\.GEOM</includeExpression> </forcedType> </forcedTypes>
升级DuckDB JDBC驱动
这类BufferUnderflowException通常是驱动的已知bug,后续版本大概率会修复。尝试升级到最新稳定版的DuckDB JDBC驱动:
<dependency> <groupId>org.duckdb</groupId> <artifactId>duckdb_jdbc</artifactId> <version>0.9.2</version> <!-- 替换为最新版本 --> </dependency>
优化临时SQL函数方案的映射问题
如果暂时需要使用ST_AsText(ST_GeomFromWKB(LOCATION.GEOM))的临时方案,可以通过别名匹配解决Record映射问题:
Result<LocationRecord> result = dsl.select( LOCATION.ID, LOCATION.NAME, ST_AsText(ST_GeomFromWKB(LOCATION.GEOM)).as(LOCATION.GEOM.getName()) ).from(LOCATION).fetchInto(LocationRecord.class);
或者自定义Converter,将WKT字符串直接转换为几何对象,并配置到代码生成器中,让自动生成的Record类直接映射为几何类型。
配置jOOQ代码生成器识别几何类型
如果使用JTS等几何库,可以直接将Blob类型的WKB列映射为几何对象:
- 添加JTS依赖
- 实现WKB与几何对象的Converter:
import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.io.WKBReader; import org.locationtech.jts.io.WKBWriter; import org.jooq.Converter; public class WkbToGeometryConverter implements Converter<byte[], Geometry> { private final WKBReader reader = new WKBReader(); private final WKBWriter writer = new WKBWriter(); @Override public Geometry from(byte[] t) { if (t == null) return null; try { return reader.read(t); } catch (Exception e) { throw new RuntimeException("解析WKB失败", e); } } @Override public byte[] to(Geometry u) { if (u == null) return null; return writer.write(u); } @Override public Class<byte[]> fromType() { return byte[].class; } @Override public Class<Geometry> toType() { return Geometry.class; } }
- 在代码生成配置中指定该Converter:
<forcedTypes> <forcedType> <userType>org.locationtech.jts.geom.Geometry</userType> <converter>com.yourpackage.WkbToGeometryConverter</converter> <includeExpression>.*\.GEOM</includeExpression> </forcedType> </forcedTypes>
内容的提问来源于stack exchange,提问作者Humaid Kidwai
相关产品推荐
相关产品推荐

