我们正在使用 JOOQ 将记录插入到具有 bytea 列的 postgresql 表中。
我们发送的字节数组约为 150Mb,我们从 Postgresql 服务器收到错误:
错误:无效的内存分配请求大小 1073741824。
深入研究代码并生成查询 JOOQ 后,我们注意到 byteArray 已转换为八进制
(org.jooq.util.postgres.PostgresUtils#toPGString(byte[]))
查询最终看起来像这样:
INSERT INTO test_table (my_data) VALUES (E'\\042\\145\\171...\\042'::bytea);
使用较小的字节数组进行测试发现,插入数据后,其大小确实是字节数组的大小,而不是八进制字符串的大小(八进制字符串更长)。
问题似乎是八进制字符串太长,以至于 postgresql 服务器在尝试将其保存到列之前无法将其转换为 bytea。
有没有办法配置 JOOQ 将
hex
字符串作为值而不是 octal
传递?
我们正在使用 JOOQ 版本
3.16.4
和 postgresql 13.9
JOOQ 配置为默认
DefaultConfiguration
。没有进行重大更改。
上面的sql取自抛出的异常:
org.jooq.impl.Tools#translate(java.lang.String, java.lang.RuntimeException)
它打印的 sql 看起来像这样:
org.jooq.exception.DataAccessException: SQL [insert into "public"."table_name" ("id", "name", "version", "description", "archived", "other_id", "jws_data") values (829720463911690240, 'v-0', 'rb-0-6HW7', null, 0, 829720463899107328, E'\\042\\145\\171\\112\\162\\141\\127\\....\135\\175'::bytea) returning "public"."table_name"."id"]; Unspecified RuntimeException
我们没有生成 SQL 插入,而是使用
org.jooq.impl.DAOImpl#insert(P)
并传递 JOOQ 生成的 Record 对象,该对象将 byteArray 作为成员之一 (jws_data
)。该名称也对应于表中的列名称。
注意:我对 SQL 进行了一些更改以隐藏确切的列名称,因此请忽略名称以及与其他 SQL 的不匹配。
toPGString:631, PostgresUtils (org.jooq.util.postgres)
sqlInline0:2044, DefaultBinding$DefaultBytesBinding (org.jooq.impl)
sqlInline0:1941, DefaultBinding$DefaultBytesBinding (org.jooq.impl)
sql:937, DefaultBinding$AbstractBinding (org.jooq.impl)
sql:929, DefaultBinding$AbstractBinding (org.jooq.impl)
accept:186, Val (org.jooq.impl)
visit0:720, DefaultRenderContext (org.jooq.impl)
visit:295, AbstractContext (org.jooq.impl)
toSQL92Values:326, FieldMapsForInsert (org.jooq.impl)
toSQL92Values:278, FieldMapsForInsert (org.jooq.impl)
accept:137, FieldMapsForInsert (org.jooq.impl)
visit0:720, DefaultRenderContext (org.jooq.impl)
visit:295, AbstractContext (org.jooq.impl)
toSQLInsert:739, InsertQueryImpl (org.jooq.impl)
accept0:624, InsertQueryImpl (org.jooq.impl)
accept:642, AbstractDMLQuery (org.jooq.impl)
visit0:720, DefaultRenderContext (org.jooq.impl)
visit:295, AbstractContext (org.jooq.impl)
getSQL0:484, AbstractQuery (org.jooq.impl)
execute:287, AbstractQuery (org.jooq.impl)
storeInsert0:191, TableRecordImpl (org.jooq.impl)
lambda$storeInsert$0:157, TableRecordImpl (org.jooq.impl)
apply:-1, TableRecordImpl$$Lambda$2120/0x0000000801a5bef8 (org.jooq.impl)
operate:143, RecordDelegate (org.jooq.impl)
storeInsert:156, TableRecordImpl (org.jooq.impl)
insert:144, TableRecordImpl (org.jooq.impl)
insert:139, TableRecordImpl (org.jooq.impl)
insert:180, DAOImpl (org.jooq.impl)
insert:156, DAOImpl (org.jooq.impl)
save:80, RDBDao (org.jfrog.bintray.distribution.rdb)
可以通过调用来重现相同的行为:
dslContext.insertInto(TEST_TABLE)
.set(MY_DATA, jws_data_byte_array)
.execute();
或者
dslContext.execute("insert into test_table (my_data) values (?)", jws_data_byte_array);
同样
toPGString:631, PostgresUtils (org.jooq.util.postgres)
被触发。
正如@Lukas Eder 提到的, 我们发现一个地方statementType被改为了
STATIC_STATEMENT
而不是默认的PREPARED_STATEMENT
。
删除此配置后,JOOQ 停止创建长八进制字符串,并且插入工作完美。