1

几个月来我一直在为一个问题苦苦挣扎。我需要从我的数据库中复制一组对象/文件并将其保存为新实例。比如说一个有很多依赖实体的学生实体。所有依赖实体中都有很多文件。所以我制作了对象的副本并调用 repositiry.save()。如果成功,此保存的整个过程最多需要 40 分钟。但是在一些随机运行中它会抛出

java.io.IOException: Closed Connection
    at oracle.jdbc.driver.OracleBlobInputStream.needBytes(OracleBlobInputStream.java:204)
    at oracle.jdbc.driver.OracleBufferedStream.readInternal(OracleBufferedStream.java:169)
    at oracle.jdbc.driver.OracleBufferedStream.read(OracleBufferedStream.java:143)
    at oracle.jdbc.driver.OracleBufferedStream.read(OracleBufferedStream.java:132)
    at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1158)
    at org.apache.commons.io.IOUtils.copy(IOUtils.java:878)
    at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1135)
    at org.apache.commons.io.IOUtils.copy(IOUtils.java:854)
    at com.*.*.*.*.hibernate.BlobUserType.nullSafeSet(BlobUserType.java:209)
    at org.hibernate.type.CustomType.nullSafeSet(CustomType.java:160)

nullSafeSet 方法如下

@Override
    public void nullSafeSet(PreparedStatement ps, Object value, int index, SharedSessionContractImplementor session)
            throws HibernateException, SQLException {

        
        if (value == null) {
            ps.setNull(index, Types.BLOB);
        } else {
            if (value instanceof FileUploadBlob) {
                FileUploadBlob fileUploadBlob = (FileUploadBlob) value;
                InputStream inputStream = fileUploadBlob.getBinaryStream();
                DatabaseMetaData dbMetaData = session.connection().getMetaData();
                String dbProductName = dbMetaData.getDatabaseProductName();
                if (dbProductName.toUpperCase().contains("ORACLE")) {
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    try {
                        IOUtils.copy(inputStream, baos);
                        InputStream is = new ByteArrayInputStream(baos.toByteArray());
                        ps.setBlob(index, is); // assume JDBC 3.0
                        
                        inputStream.close();
                        baos.close();
                    } catch (IOException e) {
                        LOG.error("Clone process interrupted due to IOException thrown :", e);
                    } catch (Exception e) {
                        LOG.error("Clone process interrupted due to Exception thrown :", e);
                    }
                }
            } else if (value instanceof Blob) {
                ps.setBlob(index, (Blob) value);
            } else {
                LOG.warn("Unknown BLOB type");
            }
        }
            
    }

我已经改变了一些配置等等,但没有任何效果。

现在作为控制器的一种解决方法,我发现异常并重试保存相同的对象(保存失败)

导致错误

org.hibernate.StaleObjectStateException:行被另一个事务更新或删除(或未保存值映射不正确)

我必须重新保存这个记录。我怎样才能做到这一点。我怎样才能回滚上一个。我是冬眠的初学者。我真的在这个问题上苦苦挣扎。请帮忙

4

1 回答 1

0

您的流程似乎试图在单个事务中执行此操作。我建议不要这样做,而是在多个较小的交易中这样做。这样您就可以从上次失败的地方继续工作,这很重要,因为看起来连接异常是由于连接打开时间过长或某些网络问题造成的。我不知道您的事务和持久性上下文管理,但是发生异常后,您应该摆脱持久性上下文(EntityManager/ Session)并创建一个新的。

于 2021-04-28T07:56:35.440 回答