1

I was struggling with an issue for months. I have a requirement to duplicate a set of objects/file from my DB and save it as new instances.Say a student entity with lot of dependent entities.So many files are there in all dependent entities. So I make the copy of the object and I am calling repositiry.save(). The whole process of this save takes upto 40 minutes if success. But in some random runs it throws

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)

The nullSafeSet method is given below

@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");
            }
        }
            
    }

I have changed somany configurations and so and so and nothing worked.

Now as a workaround from the controller I caught exception and retrying to save the same object( which was failed to save)

causing error

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)

I have to resave this record. How can I do that. How can I rollback the previous one. I am a beginner to hibernate. I am really struggling with this issue. Please help

Jens
  • 67,715
  • 15
  • 98
  • 113
Neenu Anil
  • 11
  • 1
  • try to always save the object using hibernate mapping only(i mean using Class-Association mapping in ORM) –  Apr 22 '21 at 15:15
  • TBH it wouldn't occur to me to perform such a task using Hibernate. Why not create a batch job executing SQL? – crizzis Apr 22 '21 at 19:36

1 Answers1

0

It seems that your process tries to do that within a single transaction. I would advise against that and instead do this in multiple smaller transactions. This way you can continue the work from where it last failed, which is important as it looks like the connection exception is due to the connection being open for too long or some network issue. I don't know your transaction and persistence context management, but after an exception occurs, you should get rid of the persistence context (EntityManager/Session) and create a new one.

Christian Beikov
  • 15,141
  • 2
  • 32
  • 58