Reputation: 9488
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.
Upvotes: 3
Views: 9733
Reputation: 9488
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.
Upvotes: 3
Reputation: 6706
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
Upvotes: 0
Reputation: 391
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.
Upvotes: 0