You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

jOOQ 3.19:如何按列名格式强制指定Record列类型为Long?

解决jOOQ 3.19读取SQLite大Integer字段转long的问题

针对你遇到的SQLite INTEGER字段存储超过32位数值,jOOQ默认转成int导致溢出的问题,结合jOOQ 3.19版本和无代码生成的场景,推荐两种可行方案:

方案一:全局配置自定义Binding(推荐)

通过配置ForcedType和自定义Binding,让jOOQ自动将匹配指定列名格式的INTEGER字段映射为Java Long类型,无需修改每一处SQL。

1. 实现自定义Binding

这个Binding负责处理SQLite INTEGER与Java Long的双向转换,兼容SQLite可能返回的Integer/Long类型:

import org.jooq.*;
import java.sql.*;
import java.util.Objects;

public class LongBinding implements Binding<Object, Long> {

    @Override
    public Converter<Object, Long> converter() {
        return new Converter<>() {
            @Override
            public Long from(Object t) {
                if (t == null) return null;
                // 统一将SQLite返回的数值转成Long
                return ((Number) t).longValue();
            }

            @Override
            public Object to(Long u) {
                return u;
            }

            @Override
            public Class<Object> fromType() {
                return Object.class;
            }

            @Override
            public Class<Long> toType() {
                return Long.class;
            }
        };
    }

    @Override
    public void sql(BindingSQLContext<Long> ctx) throws SQLException {
        ctx.render().visit(DSL.val(ctx.value(), SQLDataType.BIGINT)).sql("");
    }

    @Override
    public void register(BindingRegisterContext<Long> ctx) throws SQLException {
        ctx.statement().registerOutParameter(ctx.index(), Types.BIGINT);
    }

    @Override
    public void set(BindingSetStatementContext<Long> ctx) throws SQLException {
        ctx.statement().setLong(ctx.index(), Objects.requireNonNull(ctx.value()));
    }

    @Override
    public void set(BindingSetSQLOutputContext<Long> ctx) throws SQLException {
        ctx.output().writeLong(Objects.requireNonNull(ctx.value()));
    }

    @Override
    public void get(BindingGetResultSetContext<Long> ctx) throws SQLException {
        ctx.convert(converter()).value(ctx.resultSet().getLong(ctx.index()));
    }

    @Override
    public void get(BindingGetStatementContext<Long> ctx) throws SQLException {
        ctx.convert(converter()).value(ctx.statement().getLong(ctx.index()));
    }

    @Override
    public void get(BindingGetSQLInputContext<Long> ctx) throws SQLException {
        ctx.convert(converter()).value(ctx.input().readLong());
    }
}

2. 配置DSLContext时启用强制类型转换

在创建DSLContext时,通过Settings指定ForcedType,匹配你需要转换的列名格式(比如以_id结尾、包含large前缀等):

import org.jooq.*;
import org.jooq.conf.*;
import org.jooq.impl.DSL;
import org.sqlite.SQLiteDataSource;
import javax.sql.DataSource;

public class JooqSetup {
    public static DSLContext getDslContext() {
        // 初始化SQLite数据源
        SQLiteDataSource dataSource = new SQLiteDataSource();
        dataSource.setUrl("jdbc:sqlite:your-database.db");

        // 配置强制类型转换
        Settings settings = new Settings()
            .withForcedTypes(new ForcedType()
                .withName("BIGINT") // 映射为SQL BIGINT类型
                .withBinding(LongBinding.class) // 绑定自定义转换逻辑
                .withIncludeExpression(".*_id|large_\\w+") // 正则匹配目标列名,按需调整
                .withIncludeTypes("INTEGER") // 只针对SQLite的INTEGER类型生效
            );

        return DSL.using(dataSource, SQLDialect.SQLITE, settings);
    }
}

配置完成后,执行原生SQL时,匹配列名的INTEGER字段会自动被读取为Java Long类型,避免溢出问题。

方案二:手动指定字段类型(临时场景)

如果不想全局配置,也可以在fetch时手动指定字段的目标类型,直接从Record中读取Long:

DSLContext dsl = JooqSetup.getDslContext();
Result<Record> result = dsl.fetch("SELECT id, large_num FROM your_table");

for (Record record : result) {
    // 直接指定类型读取
    long id = record.get("id", Long.class);
    long largeNum = record.get("large_num", Long.class);
}

为什么之前的RecordMapper/Converter没生效?

  • RecordMapper:它是将Record映射到POJO的工具,但如果Record本身的字段已经被jOOQ转成int,映射时依然会溢出,必须先让jOOQ把字段读成Long再映射。
  • Converter:无代码生成场景下,Converter需要绑定到具体的Field对象,而原生SQL的Field是动态生成的,无法提前关联Converter,因此ForcedType+Binding是更适配的方案。

内容的提问来源于stack exchange,提问作者kmxp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 22:25:54