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

调用存储过程触发java.lang.NegativeArraySizeException:原因与修复

Spring Data JPA调用存储过程触发NegativeArraySizeException问题排查

问题场景

我使用Spring Data JPA调用Oracle存储过程,代码实现如下:

@Query(value = "DECLARE "
        + "p_transaction_header schema.transaction_header_rec := NULL; "
        + "x_voucher_id NUMBER; "
        + "x_return_status VARCHAR2(200); "
        + "x_rejection_reason VARCHAR2(4000); "
        + "BEGIN "
        + "p_transaction_header.source :=:source; "
        + "p_transaction_header.total_amount :=:totalAmount; "
        + "p_transaction_header.total_records :=:totalRecords; "
        + "p_transaction_header.external_key_identifier :=:externalKeyIdentifier; "
        + "schema.open_transaction(p_transaction_header, x_voucher_id, x_return_status, x_rejection_reason); "
        + "END", nativeQuery = true)
OpenTransactionBo openTransaction(@Param("source") String source, @Param("totalAmount") BigDecimal totalAmount,
                     @Param("totalRecords") BigDecimal totalRecords, @Param("externalKeyIdentifier") String externalKeyIdentifier);

执行时触发如下异常:

java.lang.NegativeArraySizeException

异常原因

  • 返回值映射不匹配:当前方法指定OpenTransactionBo作为返回值,但手动编写的PL/SQL块没有返回任何结果集,也没有将存储过程的输出参数绑定到返回实体。Spring Data JPA解析返回结果时,无法识别有效数据长度,导致内部数组初始化时出现负数大小,抛出该异常。
  • 输出参数未处理:存储过程的x_voucher_id、x_return_status、x_rejection_reason都是输出参数,但代码没有声明接收这些参数的方式,JPA无法正确绑定输出参数,触发解析逻辑错误。
  • 自定义类型支持问题:使用了Oracle自定义记录类型transaction_header_rec,Spring Data JPA对这类自定义类型的原生查询支持有限,参数绑定或结果解析时易出现内部逻辑错误,引发数组大小异常。

修复方案

方案1:使用@Procedure注解替代原生@Query

直接通过Spring Data JPA的@Procedure注解绑定存储过程,让框架自动处理参数映射和输出参数绑定,避免手动编写PL/SQL块:

@Procedure(procedureName = "schema.open_transaction")
void openTransaction(
    @Param("p_transaction_header") TransactionHeaderRec transactionHeader,
    @Param("x_voucher_id") Out<BigDecimal> voucherId,
    @Param("x_return_status") Out<String> returnStatus,
    @Param("x_rejection_reason") Out<String> rejectionReason
);

需要先定义对应自定义记录类型的Java类,并用Hibernate的@Struct注解映射:

@Struct(name = "TRANSACTION_HEADER_REC", schema = "SCHEMA")
public class TransactionHeaderRec {
    private String source;
    private BigDecimal totalAmount;
    private BigDecimal totalRecords;
    private String externalKeyIdentifier;
    
    // 全参构造器、getter/setter方法
}

调用后可通过Out参数获取返回值,再手动封装到OpenTransactionBo中。

方案2:修改原生查询,明确返回结果

如果坚持使用@Query,需要修改PL/SQL块,将输出参数通过SELECT语句返回,同时调整方法返回类型为Object[]:

@Query(value = "DECLARE "
        + "p_transaction_header schema.transaction_header_rec := NULL; "
        + "x_voucher_id NUMBER; "
        + "x_return_status VARCHAR2(200); "
        + "x_rejection_reason VARCHAR2(4000); "
        + "BEGIN "
        + "p_transaction_header.source :=:source; "
        + "p_transaction_header.total_amount :=:totalAmount; "
        + "p_transaction_header.total_records :=:totalRecords; "
        + "p_transaction_header.external_key_identifier :=:externalKeyIdentifier; "
        + "schema.open_transaction(p_transaction_header, x_voucher_id, x_return_status, x_rejection_reason); "
        + "SELECT x_voucher_id, x_return_status, x_rejection_reason FROM DUAL; "
        + "END", nativeQuery = true)
Object[] openTransaction(
    @Param("source") String source,
    @Param("totalAmount") BigDecimal totalAmount,
    @Param("totalRecords") BigDecimal totalRecords,
    @Param("externalKeyIdentifier") String externalKeyIdentifier
);

调用后将Object[]中的元素手动映射到OpenTransactionBo对象的对应字段。

方案3:升级依赖版本

部分旧版本的Hibernate或Oracle JDBC驱动对自定义类型的处理存在bug,升级到最新稳定版(如Hibernate 5.6+、Oracle JDBC 19c及以上),可以修复这类底层解析异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 08:27:05