Caused by: org.postgresql.util.PSQLException: An I/O error occurred while sending to the backend.
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:382)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:490)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:408)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:166)
at org.postgresql.jdbc.PgPreparedStatement.execute(PgPreparedStatement.java:155)
at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_execute(FilterChainImpl.java:3446)
at com.alibaba.druid.filter.FilterEventAdapter.preparedStatement_execute(FilterEventAdapter.java:434)
at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_execute(FilterChainImpl.java:3444)
at com.alibaba.druid.proxy.jdbc.PreparedStatementProxyImpl.execute(PreparedStatementProxyImpl.java:152)
at com.alibaba.druid.pool.DruidPooledPreparedStatement.execute(DruidPooledPreparedStatement.java:483)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:64)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79)
at sun.reflect.GeneratedMethodAccessor151.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64)
at com.sun.proxy.$Proxy295.query(Unknown Source)
at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63)
at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325)
at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156)
at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62)
at com.sun.proxy.$Proxy294.query(Unknown Source)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140)
at sun.reflect.GeneratedMethodAccessor149.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427)
... 25 common frames omitted
Caused by: java.io.IOException: Tried to send an out-of-range integer as a 2-byte value: 39176
at org.postgresql.core.PGStream.sendInteger2(PGStream.java:359)
at org.postgresql.core.v3.QueryExecutorImpl.sendParse(QueryExecutorImpl.java:1604)
at org.postgresql.core.v3.QueryExecutorImpl.sendOneQuery(QueryExecutorImpl.java:1929)
at org.postgresql.core.v3.QueryExecutorImpl.sendQuery(QueryExecutorImpl.java:1487)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:347)
... 54 common frames omitted
遇到这种错误该如何解决呢?
分析:此错误的核心原因是 PostgreSQL JDBC驱动对协议参数值的限制。具体表现为:
- 参数值溢出:错误日志中的
Tried to send an out-of-range integer as a 2-byte value: 39176
表明程序尝试发送的整数值超过了 2 字节(即超过 32767)的表示范围。 - 批量操作数据量过大:常见于批量插入或查询时,单次传输的 SQL 参数数量或数据行数超过 PostgreSQL 协议限制。
解决方式:检查代码,看是否有查询之类的语句导致语句量过大,导致资源耗尽。
问题示例:
// 省去service层查询,直接通过wrapper条件进行查询 LambdaQueryWrapper<SlotEntity> queryWrapper = Wrappers.lambdaQuery(); mapSlotPairs.forEach(item -> { queryWrapper.or(wrapper -> wrapper.eq(SlotEntity::getMapCode, item.get("mapCode")).eq(SlotEntity::getSlotCode, item.get("slotCode"))); }); List<SlotEntity> oldSlotEntityList = SLOT_SERVICE.list(queryWrapper);原因:我表中的数据量有2w条,导致查询语句过长,超过了pgsql默认限制。
解决方式:(批量处理)
// 每批次处理 1000 条 int batchSize = 1000; List<SlotEntity> oldSlotEntityList = new ArrayList<>(); for (int i = 0; i < mapSlotPairs.size(); i += batchSize) { List<Map<String, String>> subList = mapSlotPairs.subList(i, Math.min(i + batchSize, mapSlotPairs.size())); LambdaQueryWrapper<SlotEntity> batchWrapper = Wrappers.lambdaQuery(); subList.forEach(item -> { batchWrapper.or(wrapper -> wrapper .eq(SlotEntity::getMapCode, item.get("mapCode")) .eq(SlotEntity::getSlotCode, item.get("slotCode"))); }); oldSlotEntityList.addAll(SLOT_SERVICE.list(batchWrapper)); }