Why is Hibernate so inefficient in handling large streams in JBoss EAP 6.0.0?

Solution Verified - Updated -

Issue

Boundary conditions:

  • ORACLE 11g XE with the latest JDBC driver
  • Binary file size: 250MB
  • CPU consumption includes database running on the same machine like the test

I compared 4 variations of BLOB handling:

  • JPA byte[]
  • JPA java.sql.Blob streaming
  • JDBC streaming (ResultSet.setBinaryStream)
  • JDBC byte[]

Results:

Variant JPA byte[] JPA Blob stream JDBC byte[] JDBC stream
Elapsed Time (s) 20 50 25 30
Max Memory (MB) 750 750 600 5
Average Memory (MB) 600 270 600 5
CPU Load (%) 80 60 65 60
CPU Worktime (s) 16 30 16 18

My Questions:

  • Is it neccessary that JPA java.sql.Blob with Hibernate needs so much memory? Do there exists a setting or hint to get an behavior like JDBC streaming?
  • What pitfalls await me if i make a Hibernate user type to use JDBC streaming?
    Overall question:
  • How to get a streamable, serializeable and Hibernate mapable BLOB-Type?

Relevant code snipet (JPA byte[]):
Code:

   @Lob
   @Column(length = 100000000)
   public byte[] getBigBlob() {
      return bigBlob;
   }
...
  public static void testBlobAsArray() throws Exception {
      EntityManager em = JpaUtil.getEntityManager();

      B_VerschiedeneLobs o = new B_VerschiedeneLobs();

      // First i have to load the bytes into memory
      byte[] bigArray = FileUtils.readFileToByteArray(testFile);

      o.setBigBlob(bigArray);

      em.getTransaction().begin();
      em.persist(o);
      em.getTransaction().commit();
  }

Relevant code snipet (JPA java.sql.Blob streaming):
Code:

   @Lob
   @Column(length = 100000000)
   public Blob getBigStreamedBlob() {
      return bigStreamedBlob;
   }
  ...
   public static void testBlobAsStream() throws Exception {
      EntityManager em = JpaUtil.getEntityManager();

      B_VerschiedeneLobs o = new B_VerschiedeneLobs();

      LobHelper lh = em.unwrap(Session.class).getLobHelper();

      FileInputStream fis = new FileInputStream(testFile);

      em.getTransaction().begin();

      Blob blob = lh.createBlob(fis, -1);
      // blob = SerializableBlobProxy.generateProxy( blob );
      o.setBigStreamedBlob(blob);

      em.persist(o);
      em.getTransaction().commit();

      fis.close();
   }

Relevant code snipet (JDBC byte[]):
Code:

   public static void testBlobArrayWithJdbc() {
      Connection con = null;
      try {
         DriverConfig config = JpaUtil.loadDriverConfigFromPersistenceXml();

         oracle.jdbc.pool.OracleDataSource ds = new oracle.jdbc.pool.OracleDataSource();
         ds.setURL(config.url);
         ds.setUser(config.user);
         ds.setPassword(config.password);
         con = ds.getConnection();

         // Deleting the record for re-testing
         Statement sta = con.createStatement();
         sta.executeUpdate("DELETE FROM B_VerschiedeneLobs WHERE id = '1'");

         // Inserting CLOB value with a PreparedStatement
         PreparedStatement ps = con
               .prepareStatement("insert into B_VerschiedeneLobs (bigStreamedBlob, id) values (?, 1)");

         byte[] bigArray = FileUtils.readFileToByteArray(testFile);

         ps.setBytes(1, bigArray);

         int count = ps.executeUpdate();
         ps.close();

         sta.close();
         con.close();
      } catch (Exception e) {
         System.err.println("Exception: " + e.getMessage());
         e.printStackTrace();
      }
   }

Relevant code snipet (JDBC stream):
Code:

   public static void testBlobStreamWithJdbc() {
      Connection con = null;
      try {
         DriverConfig config = JpaUtil.loadDriverConfigFromPersistenceXml();

         oracle.jdbc.pool.OracleDataSource ds = new oracle.jdbc.pool.OracleDataSource();
         ds.setURL(config.url);
         ds.setUser(config.user);
         ds.setPassword(config.password);
         con = ds.getConnection();

         // Inserting CLOB value with a PreparedStatement
         PreparedStatement ps = con
               .prepareStatement("insert into B_VerschiedeneLobs (bigStreamedBlob, id) values (?, 1)");

         File fileIn = new File("test.txt");
         InputStream bodyIn = new FileInputStream(fileIn);

         ps.setBinaryStream(1, bodyIn);

         int count = ps.executeUpdate();
         bodyIn.close();
         ps.close();

         sta.close();
         con.close();
      } catch (Exception e) {
         System.err.println("Exception: " + e.getMessage());
         e.printStackTrace();
      }
   }

Environment

  • JBoss Enterprise Application Platform(EAP) 6.0.0

Subscriber exclusive content

A Red Hat subscription provides unlimited access to our knowledgebase of over 48,000 articles and solutions.

Current Customers and Partners

Log in for full access

Log In
Close

Welcome! Check out the Getting Started with Red Hat page for quick tours and guides for common tasks.