调用带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
相关产品推荐
相关产品推荐

