Thursday, August 31, 2006

hellish Hibernate blobs under WebLogic with Oracle

There were bugs in the Oracle driver that caused problems reading blobs under Hibernate. Basically the byte array can be written to Oracle, but what's read back from Oracle is always 86 bytes which is the Oracle Blob locator (pointer), not the blob.

Now, this has long since been fixed by Oracle (thin on or before 10.1.0.4) and Hibernate (on or before 3.05), yet the problem continues to exist under WebLogic 9.1. Stack trace looks something like BEA thinks they have a better way of handling storing blobs than Oracle (see CR112225). In any event, one workaround is:
-Dhibernate.jdbc.use_streams_for_binary=true
<property name="content" type="binary" column="CONTENT" />


(note, in 3.05 at least, this property is not read from the hibernate configuration file, regardless of what the hibernate documentation actually says).

But perhaps would be better to actually follow the CR112225 advice and use
<serialize-byte-array-to-oracle-blob>

The WebLogic description of CR11225 is correct as to the cause, but is misleading and inaccurate regarding the extent or consequence: their example of using weblogic.jdbc.common.OracleBloc is merely an example, not the cause, and the problem was seen with blobs created and stored under WebLogic 9.1, not "some other vendor".

From http://e-docs.bea.com/wls/docs81/pdf/notes.pdf:


WebLogic Server 8.1 Release Notes

Resolved Problems for Service Pack 2
7-22

CR112225

For BLOBs, in the generated code, WebLogic Server calls
ObjectOutputStream.writeObject and
ObjectInputStream.readObject to serialize/deserialize the object before
writing/reading it to the database. These calls add extra header information. The
writeObject method writes the class of the object, the signature of the class, the values
of the non-transient and non-static fields of the class, and all of its supertypes are written.
(This is the reason for the extra header seen in the database.) These calls do not cause a
problem when customers are using only WebLogic Server to set and get BLOBs, because it
uses readObject to convert the bytes into the appropriate object, which needs that extra
header information. However, if the BLOB has been inserted directly into the database by
some other vendor or programmer using:
OutputStream os = ((weblogic.jdbc.common.OracleBlob)
lob).getBinaryOutputStream(); os.write(this.tiffImage); //
byte[] tiffImage
then problems may occur because WebLogic Server uses readObject and the header
information is missing. For the data inserted using WebLogic Server , the other programs that
would read the bytes directly get the extra header information and fail.
<serialize-byte-array-to-oracle-blob> has been added to control the
persistence behavior. This element is used to specify whether a cmp-field of type
byte[] mapped to an OracleBlob should be serialized. The tag has been added to a new
compatibility stanza in the weblogic-cmp-rdbms descriptor.
Note that, in versions prior to SP2, the default behavior was to serialize a cmp-field of
type byte[] mapped to an OracleBlob. Now, the byte[] is written directly to the
OutputStream obtained from the BLOB. To revert to the old behavior, set the value of this
tag to true.

Fixed Release: 8.1 SP2

No comments: