3

I am attempting to get Hibernate to lazy load some clobs. The loading portion is working just fine. The issue is when I try to create a new one. I started with advice from Blob lazy loading

Here are my mappings (Note the table structure is really really bad, there are multiple clobs on this table -- this example is simplified from my real model...).

@Entity @Table("TABLE_1")
public class BadDBDesign {
  @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column("table_id")
  private long key;
  
  @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
  @JoinColumn(name = "table_id", referencedColumnName = "table_id", 
              insertable = true, updatable = false)
  private BlobWrapperA;

  @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
  @JoinColumn(name = "table_id", referencedColumnName = "table_id",
              insertable = true, updatable = false)
  private BlobWrapperB;
}

@Entity @Table(name = "TABLE_1")
public class BlobWrapperA {
  @Lob
  @Column(name = "col_A", nullable = false)
  @Type(type = "org.springframework.orm.hibernate3.support.BlobByteArrayType")
  private byte[] blobColA;

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "table_id")
  private long Key;
}

@Entity @Table(name = "TABLE_1")
public class BlobWrapperB {
  @Lob
  @Column(name = "col_B", nullable = false)
  @Type(type = "org.springframework.orm.hibernate3.support.BlobByteArrayType")
  private byte[] blobColB;

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "table_id")
  private long Key;
}

Application boots just fine, am able to retrieve the data without loading the clobs (am able to retrieve them when needed via lazy loading), but when I attempt to create the new ones I receive the following stacktrace:

Hibernate: 
  insert 
  into
    TABLE_1
    (key, col_A, col_B) 
values
    (?, ?, ?)
2011-08-31 17:35:09,089 [http-8080-1] DEBUG org.springframework.jdbc.support.lob.DefaultLobHandler IP134.167.141.34 CV#f2a597b2-a185-4e89 P#71252 - Set bytes for BLOB with length 7136
2011-08-31 17:35:16,441 [http-8080-1] DEBUG org.springframework.jdbc.support.lob.DefaultLobHandler IP134.167.141.34 CV#f2a597b2-a185-4e89 P#71252 - Set bytes for BLOB with length 10946
Aug 31, 2011 5:35:50 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet online threw exception java.sql.SQLIntegrityConstraintViolationException: ORA-01400: cannot insert NULL into ("SCHEMA"."TABLE_1"."COL_A")

at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:440)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:837)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:445)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:191)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:523)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:207)
at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1010)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1315)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3576)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3657)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1350)
at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)

Note the important piece where we see the lengths of the clobs immediately after the Hibernate insert statement from the generated SQL.

Edit: After looking at this early this morning, I realized that the issue was due to one of the Blobs had to be mapped with @JoinColumn(insertable = false, updatable = false), otherwise Hibernate would not start. As such of course it was attempting to insert Null into this column. So the new question becomes, can you lazily MULTIPLE clobs on a single table (using the same key). I'm guessing without a table redesign, I'm pretty much out of luck unless Oracle fixes the driver.

Community
  • 1
  • 1
Scott
  • 9,458
  • 7
  • 54
  • 81
  • 1
    Do you have a small program that shows how you are trying to insert the data? This would be helpful to see. – Ian Dallas Aug 31 '11 at 22:02
  • Unfortunately I don't. I believe that I'm going to have to though as this could be an issue with the oracle driver. I'm attempting to use the OracleLobHanlder instead of the DefaultLobHandler currently. The insert is done with: getHibernateTemplate().saveOrUpdate(badDBDesign); – Scott Aug 31 '11 at 22:09

3 Answers3

3

As much as it makes me want to vomit we needed to get this functionality without modifying the Database.

As such, I pulled out the common pieces into an Abstract class like such:

@MappedSuperclass @Table("TABLE_1")
public class BadDBDesign {
  @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column("table_id")
  private long key;

  @Column("small_value")
  private String smallVarChar2Field;
}

The problem is I then have to extend this class for each of our blobs :( Thus our extended classes loook like:

public class BlobA extends BadDBDesign {
  @Lob @Column("col_a")
  @Type(type ="org.springframework.orm.hibernate3.support.BlobByteArrayType")
  private byte[] blobColA;
}

public class BlobB extends BadDBDesign {
  @Lob @Column("col_b")
  @Type(type ="org.springframework.orm.hibernate3.support.BlobByteArrayType")
  private byte[] blobColB;
}

Luckily we don't have any location where we more than one clob on any given page. This is still a maintenance nightmare, but was an acceptable trade-off (for the time-being) on getting the loads done more efficiently. I created DAO's for these, which the project didn't have prior; hopefully this will push the team in a good direction towards a proper abstraction layer, and we can hopefully completely remove these wasted POJOs in a future release.

Scott
  • 9,458
  • 7
  • 54
  • 81
0

Looks like in your BlobWrapperA class you have "nullable = false" set on that column. Or the column has a null constraint on the table itself in the database.

Jason Holmberg
  • 291
  • 2
  • 17
0

Oracle and Hibernate hate each other when it comes to LOB types, which stems from the fact that the Oracle driver is garbage. I believe I've run across this before, you should try setting the following system properties:

hibernate.jdbc.use_streams_for_binary=true
hibernate.jdbc.batch_size=0
jonathan.cone
  • 6,592
  • 2
  • 30
  • 30
  • Unfortunately that results in the same error, albeit with the same log on the BLOB lengths. – Scott Aug 31 '11 at 22:50
  • @Scott, Does the OracleDialect you're using match the version of Oracle DB you're using? Oracle9Dialect, Oracle9iDialect and Oracle10gDialect are the options I believe. Are you using the 11g driver by chance? – jonathan.cone Aug 31 '11 at 23:29
  • Oracle dialcet is set to 10g. We are using the 11g driver, connecting to an 11g database. – Scott Sep 01 '11 at 10:22