java.sql.SQLRecoverableException:从 Oracle 数据库接收 blob 字段期间关闭连接

java.sql.SQLRecoverableException: Closed Connection during receiving blob field from oracle database

我在从 Oracle 数据库接收 blob 字段时遇到了一个奇怪的问题:“SQLRecoverableException: Closed Connection

描述此异常的堆栈跟踪:

java.sql.SQLRecoverableException: Closed Connection
    at oracle.jdbc.driver.OracleBlob.getDBAccess(OracleBlob.java:960) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.OracleBlob.getBinaryStream(OracleBlob.java:319) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.OracleBlob.getBinaryStream(OracleBlob.java:300) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.sql.BLOB.getBinaryStream(BLOB.java:316) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_221]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_221]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_221]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_221]
    at org.hibernate.engine.jdbc.SerializableBlobProxy.invoke(SerializableBlobProxy.java:60) ~[hibernate-core-5.3.18.Final.jar:5.3.18.Final]
    at com.sun.proxy.$Proxy142.getBinaryStream(Unknown Source) ~[?:?]
    at com.xxx.yyy.util.KeystoreHelper.loadKeyStore(KeystoreHelper.java:89) [cphcore-3.23.0.23-SNAPSHOT.jar:?]
    at com.xxx.yyy.bp.job.substep.ProcessIF2Files.getChannelUnsealer(IFB2UnsealFiles.java:207) [classes/:?]
    at com.xxx.yyy.bp.job.substep.ProcessIF2Files.access(IFB2UnsealFiles.java:198) [classes/:?]
    at com.xxx.yyy.bp.job.substep.ProcessIF2Files.execute(IFB2UnsealFiles.java:86) [classes/:?]
    at com.xxx.yyy.bp.job.substep.ProcessIF2Files.execute(IFB2UnsealFiles.java:1) [classes/:?]

源代码:classKeystoreHelper方法loadKeyStore:

(...)

    Blob keystoreBlob = keystore.getKeystoreData();
    if (keystoreBlob == null || keystoreBlob.length() == 0) {
      log.error("Keystore data is empty");
      throw new KeystoreAccessException(keystore, "Keystore data is empty", null);
    }

    inputStream = keystore.getKeystoreData().getBinaryStream(); // line 89 - Exception
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    IOUtils.copy(inputStream, outputStream);
    inputStream.close();
    outputStream.close();
    byte[] keystoreData = outputStream.toByteArray();

    inputStream = new ByteArrayInputStream(keystoreData);
    
(...)

变量的源代码 - 密钥库,class DbKeystore(实体),方法 getKeystoreData:

(...)
    private java.sql.Blob keystoreData;
    
    public java.sql.Blob getKeystoreData() {
        return this.keystoreData;
    }
    
    public void setKeystoreData(java.sql.Blob keystoreData) {
        this.keystoreData = keystoreData;
    }
(...)

大家遇到过类似的问题吗? 感谢您的帮助:)

这很可能是由于底层 JDBC 连接被放回连接池造成的。确保用于加载实体的 EntityManagerSession 在您访问 blob 时仍然处于活动状态。

我正在与@lmetrak 一起工作,最后我弄清楚出了什么问题。 我们的应用程序支持 Oracle 和 MSSQL 数据库。这个错误只有在我们使用Oracle时才会出现,因为它是由oracle的BLOB实现引起的。

@lmetrak 发布了 KeystoreHelper.class 的和平。在这里我们没有交易。我们在上一步中为数据库获取了 Keystore 实体,我们关闭了事务并将实体传递给 KeystoreHelper class.

oracle.sql.BLOB 包含有关用于从数据库中获取实体的连接的信息。因此,当我们请求 BinaryStream 时,blob 会尝试连接到数据库以下载日期,因为它不仅仅是代理。它不会尝试从连接池中获取打开的连接,但会尝试使用用于获取密钥库实体的相同连接。有时会发生同时关闭连接,然后出现错误。我不确定什么是 MSSQL 策略,但他们的 BLOB 实现不包含有关连接的信息,因此不存在该问题。

我们的解决方案是将 Keystore.keystoreData 文件类型从 BLOB 更改为 byte[]。 现在它适用于 Oracle 和 MSSQL。

(...)

     byte[] keystoreData = keystore.getKeystoreData();
     /*A few checks*/
     inputStream = new ByteArrayInputStream(keystore.getKeystoreData());
     ByteArrayOutputStream outputStream= new ByteArrayOutputStream();
     IOUtils.copy(inputStream , outputStream);
     inputStream .close();
     outputStream.close();
     byte[] myKeystoreData = myBos.toByteArray();
     inputStream = new ByteArrayInputStream(myKeystoreData);
    
(...)