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

调用带Oracle数组参数的存储过程时出现SerializationException异常

问题分析与解决思路

问题根源

你创建的OracleArray实例内部持有了T4CConnection的引用,而Hibernate在执行存储过程时,会尝试对参数进行序列化操作(比如用于二级缓存或参数持久化逻辑),但oracle.jdbc.driver.T4CConnection并未实现Serializable接口,因此触发了序列化异常。

解决方法

1. 利用Hibernate Session管理Connection与Array对象

不要直接从数据源获取Connection创建数组,而是通过Hibernate Session的doWork方法操作,让Hibernate管理对象生命周期,避免序列化时携带Connection引用:

public List<MyEntity> fetchMyEntityAttrs(List<String> idList) {
    StoredProcedureQuery procedureQuery = entityManager
        .createStoredProcedureQuery("my_entity_pkg.get_attrs", MyEntity.class)
        .registerStoredProcedureParameter("array", ARRAY.class, ParameterMode.IN)
        .registerStoredProcedureParameter("cursor", void.class, ParameterMode.REF_CURSOR);

    Session session = entityManager.unwrap(Session.class);
    session.doWork(connection -> {
        OracleConnection oracleConnection = connection.unwrap(OracleConnection.class);
        Array oracleArray = oracleConnection.createOracleArray("VARCHAR2_ARRAY", idList.toArray());
        procedureQuery.setParameter("array", oracleArray);
    });

    procedureQuery.execute();
    return procedureQuery.getResultList();
}

2. 直接使用JDBC CallableStatement执行存储过程

绕开Hibernate的StoredProcedureQuery,完全掌控参数与Connection的生命周期,避免Hibernate的序列化逻辑:

public List<MyEntity> fetchMyEntityAttrs(List<String> idList) {
    List<MyEntity> resultList = new ArrayList<>();
    try (Connection connection = datasourceConfiguration.dataSource().getConnection()) {
        OracleConnection oracleConnection = connection.unwrap(OracleConnection.class);
        Array oracleArray = oracleConnection.createOracleArray("VARCHAR2_ARRAY", idList.toArray());
        
        String sql = "{ call my_entity_pkg.get_attrs(?, ?) }";
        try (CallableStatement stmt = connection.prepareCall(sql)) {
            stmt.setArray(1, oracleArray);
            stmt.registerOutParameter(2, OracleTypes.CURSOR);
            stmt.execute();
            
            // 手动映射结果集到MyEntity
            try (ResultSet rs = (ResultSet) stmt.getObject(2)) {
                while (rs.next()) {
                    MyEntity entity = new MyEntity();
                    // 根据实际字段映射,示例:entity.setId(rs.getString("ID"));
                    resultList.add(entity);
                }
            }
        }
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
    return resultList;
}

3. 检查Hibernate缓存配置

如果开启了二级缓存(hibernate.cache.use_second_level_cache=true),可能会触发参数序列化缓存。若业务不需要二级缓存,可关闭该配置;若必须保留,优先采用前两种方法解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 09:01:12