jooq 记录在获取数据时是不是使用列索引?

Posted

技术标签:

【中文标题】jooq 记录在获取数据时是不是使用列索引?【英文标题】:Does jooq record use column indexes when fetching data?jooq 记录在获取数据时是否使用列索引? 【发布时间】:2021-12-23 20:00:19 【问题描述】:

我正在调查一个问题,我们看到与 jooq 试图填充生成的 Record 类相关的奇怪异常,因为它使用 java.sql.ResultSet::getXXX(int)(基于列索引) 来获取数据。

我可以分享的堆栈跟踪部分如下所示:

Caused by: java.sql.SQLDataException: Value 'ABC' is outside of valid range for type java.lang.Byte
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:114)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:63)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:73)
    at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:92)
    at com.mysql.cj.jdbc.result.ResultSetImpl.getObject(ResultSetImpl.java:1423)
    at com.mysql.cj.jdbc.result.ResultSetImpl.getByte(ResultSetImpl.java:710)
    at com.zaxxer.hikari.pool.HikariProxyResultSet.getByte(HikariProxyResultSet.java)
    at org.jooq.tools.jdbc.DefaultResultSet.getByte(DefaultResultSet.java:124)
    at org.jooq.tools.jdbc.DefaultResultSet.getByte(DefaultResultSet.java:124)
    at org.jooq.impl.CursorImpl$CursorResultSet.getByte(CursorImpl.java:688)
    at org.jooq.impl.DefaultBinding$DefaultByteBinding.get0(DefaultBinding.java:1783)
    at org.jooq.impl.DefaultBinding$DefaultByteBinding.get0(DefaultBinding.java:1755)
    at org.jooq.impl.DefaultBinding$AbstractBinding.get(DefaultBinding.java:871)
    at org.jooq.impl.CursorImpl$CursorIterator$CursorRecordInitialiser.setValue(CursorImpl.java:1725)

这肯定是使用错误的列索引导致的列不匹配。

问题出现是因为我们在不断发展的架构上使用记录,因此基础表包含记录定义中不可用的列。

请注意,触发此操作的实际代码是:

jooq.insertInto(TABLE)
    .set(TABLE.COL, "ABC")
    .returning(TABLE.asterisk())
    .fetchOne();

这里让我有点害怕的是,如果它确实按设计使用列索引,那将使架构演变有些困难(如何从正在运行的应用程序中删除列)。

长话短说(对不起),问题是:jooq 是否在 jooq-generator 生成的记录中使用列索引,有没有办法使用列名代替?

我注意到的一件事是,当我比较https://www.jooq.org/doc/3.14/manual/code-generation/codegen-records/ 的文档时,显示的生成记录与生成器实际生成的记录不匹配。文档显示的方法如下:

// Every column generates a setter and a getter
@Override
public void setId(Integer value) 
    setValue(BOOK.ID, value);

但实际上生成的代码看起来像(取自jOOQ-examples):

/**
 * Setter for <code>PUBLIC.BOOK.ID</code>.
 */
public void setId(Integer value) 
    set(0, value);

顺便说一句,我们使用的是 jooq 3.14.15。

【问题讨论】:

我试图在一个测试用例中重现我的问题,我在测试期间向基础表添加了一个列,但到目前为止我无法重现该问题,所以我怀疑真正的问题可能与我最初的评估不同。 【参考方案1】:

好的,这是一个本地错误。真正导致问题的原因是我们的代码写成:

jooq.insertInto(TABLE)
    .set(TABLE.COL, "ABC")
    .returning(TABLE.asterisk())
    .fetchOne();

TABLE.asterisk() 搞砸了(因为在包含额外列的数据库上,它不会返回 jooq 所期望的)。幸运的是,删除它解决了问题,所以我们的代码现在看起来像:

jooq.insertInto(TABLE)
    .set(TABLE.COL, "ABC")
    .returning()
    .fetchOne();

【讨论】:

是的,这就是造成这种情况的原因,请参阅最近对文档的改进,解释行为:github.com/jOOQ/jOOQ/issues/12620 是的,正如您在github.com/jOOQ/jOOQ/issues/8886 中推荐的那样,您还可以在许多情况下使用 TABLE.fields() ,这将给出 jooq 知道的字段列表,这在使用连接时很有用例如:select(TABLE1.fields()).from(TABLE1).innerJoin(TABLE2).onKey().fetch().into(Table1Record.class) 不过,这看起来像是 semi join 的情况

以上是关于jooq 记录在获取数据时是不是使用列索引?的主要内容,如果未能解决你的问题,请参考以下文章

如何按列名获取列索引?

获取 java.sql.SQLException:插入表时列索引无效

如何使用 jQuery 获取表列索引?

pandas读取csv数据header参数指定作为列索引的行索引列表形成复合(多层)列索引使用xs函数获取行切面数据(level参数指定行层索引列表key参数指定索引值列表)

从熊猫数据框的列索引中获取字符串列表

c# winform编程 数据库 .net 怎么获取datagridview中选中列的列索引?