暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL数据库-Tried to send an out-of-range integer as a 2-byte value: 53568报错

业务侧反馈,因为某业务积攒的单量太大,导致在数据批量入库的时候,产生如下报错,主要报错信息是:请求参数的整体大小不能超过2byte。

Tried to send an out-of-range integer as a 2-byte value: 53568

image.png

这个报错初步看起来,有个“out-of-range integer”,可能大家第一个想到的可能是:是不是表的字段不够长,但是插入的数据太长了导致的?但其实简单测试下就可以发现,列的长度不够,报的错误和这个是不一样的。

postgres=# create table t1(id int2);
CREATE TABLE
postgres=# insert into t1 values(53568);
ERROR:  smallint out of range
CONTEXT:  referenced column: id

postgres=# select 53568::int2;
ERROR:  smallint out of range
CONTEXT:  referenced column: int2

除此之外,查看了报错的这张表的表结构,除了一列为数字类型外,其余字段均为字符或者时间类型,而这一数字类型的列,根据业务场景来看,一般不会有超出长度的数值。

这个报错是驱动报出来的,可以查看下pgjdbc的驱动的代码,pgjdbc的源码地址为:https://github.com/pgjdbc/pgjdbc

报错的位置只有一处,如下是42.3.10版本pgjdbc的报错部分,其中,判断条件里Short.MIN_VALUE和Short.MAX_VALUE的值分别为-32768和32767,表示SQL 解析过程中, SQL中的参数的个数最大不超过32767。

... public final class Short extends Number implements Comparable<Short> { public static final short MIN_VALUE = -32768; public static final short MAX_VALUE = 32767; ... ... /** * Sends a 2-byte integer (short) to the back end. * * @param val the integer to be sent * @throws IOException if an I/O error occurs or {@code val} cannot be encoded in 2 bytes */ public void sendInteger2(int val) throws IOException { if (val < Short.MIN_VALUE || val > Short.MAX_VALUE) { throw new IOException("Tried to send an out-of-range integer as a 2-byte value: " + val); } int2Buf[0] = (byte) (val >>> 8); int2Buf[1] = (byte) val; pgOutput.write(int2Buf); } ... ...

如下是42.4.0版本pgjdbc的报错部分,其中,判断条件里将之前版本的MIN_VALUE和MAX_VALUE直接替换成了0和65535,表示SQL 解析过程中, SQL中的参数的个数最大不超过65535。

/** * Sends a 2-byte integer (short) to the back end. * * @param val the integer to be sent * @throws IOException if an I/O error occurs or {@code val} cannot be encoded in 2 bytes */ public void sendInteger2(int val) throws IOException { if (val < 0 || val > 65535) { throw new IllegalArgumentException("Tried to send an out-of-range integer as a 2-byte unsigned int value: " + val); } int2Buf[0] = (byte) (val >>> 8); int2Buf[1] = (byte) val; pgOutput.write(int2Buf); }

而进一步和业务确认,果然他们使用的pgjdbc驱动的版本比较低,并且其实日志的报错部分往上翻,其实也能大致看出这个报错的SQL,涉及到了大量的绑定变量。业务同事反馈,交易笔数大概几千比,但是每比交易涉及到很多绑定变量,这些总和超出了他们使用的pgjdbc驱动的参数个数限制。

image.png

因此,解决方案其实有两种:一种使用较高版本的pgjdbc驱动(42.4.0+),驱动支持的参数的最大个数提升到了65535,会很大程度上减少此类报错。一种是采用jdbc或者MyBatis等持久化框架提供的批量执行接口进行批量操作。调整业务,对拼接的SQL的逻辑进一步拆分,减少单个SQL绑定变量个数。

最后修改时间:2025-01-02 12:23:01
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论