We're using Hibernate on a legacy database, using the LONG RAW datatype to store some binary data. It has two entities with bidirectional associations: Document and Revision (a document has many revisions). The Revision entity has the LONG RAW data column, which eventually becomes a byte-array in the corresponding Revision class.
When trying to retrieve a Document object we get a java.sql.SQLException: "Datastrømmen er allerede lukket", which is in norwergian at means something like "The data stream is already closed".
Our first shot at debugging this, we removed the associations between Document and Revision and tried to retrieve only one single Revision. This worked with no erros. Digging into the Hibernate code we eventully discovered a method that might have causeed this problem:
Excerpt from
net.sf.hibernate.loader.Loader.getKeyFromResultSet(int i, Loadable persister, Serializable id, ResultSet rs, SessionImplementor session):
Code:
Type idType = persister.getIdentifierType();
resultId = (Serializable) idType.nullSafeGet(rs, suffixedKeyColumns[i], session, null); //problematic for <key-many-to-one>!
if ( id!=null && resultId!=null && id.equals(resultId) ) resultId = id; //use the id passed in
Commenting out this code and recompiling Hibernate made our program work.
As we didn't want to alter the Hibernate code and possible create new types of problems, we tried to remove the bidirectional association in our code instead. This made our program work correctly. That is, we rewrote our code so that a Document object still has a collection of revisions, but a Revision object does no longer have a reference to its parent Document.
Does anyone have any idea why this error disappears when we removed the bidirectional association? Would it be safe to remove the code in Loader.getKeyFromResultSet(), as suggested above?
More detailed info below.
Cheers,
Anders.
Hibernate version: 2.1.8Mapping documents: Code:
<hibernate-mapping>
<class name="no.test.Revision" table="REVISION">
<composite-id name="revisionPK" class="no.test.persistent.RevisionPK">
<key-property name="revnum" column="REVNUM" type="java.math.BigDecimal" length="22"> </key-property>
<key-property name="documentId" column="DOCUMENT_ID" type="java.math.BigDecimal" length="22"> </key-property>
</composite-id>
<property name="document" column="DOCUMENT" type="binary" /> <many-to-one name="parentDocument" column="DOCUMENT_ID" class="no.test.persistent.Document" insert="false" update="false" not-null="true" />
</class>
<class name="no.test.persistent.Document" table="DOCUMENT">
<id name="id" type="java.math.BigDecimal" column="ID">
<generator class="assigned" />
</id>
<bag name="revisions" inverse="true" lazy="true" >
<key column="DOCUMENT_ID" />
<one-to-many class="no.test.persistent.Revision" />
</bag>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
Document document = (Document) session.load(Document.class, new BigDecimal(id));
Full stack trace of any exception that occurs:Code:
SEVERE: Datastrømmen er allerede lukket
28.feb.2005 11:33:52 net.sf.hibernate.collection.PersistentCollection initialize
SEVERE: Failed to lazily initialize a collection
net.sf.hibernate.exception.GenericJDBCException: could not load: [no.test.persistent.Revision#no.test.persistent.RevisionPK@b]
at net.sf.hibernate.exception.ErrorCodeConverter.handledNonSpecificException(ErrorCodeConverter.java:90)
at net.sf.hibernate.exception.ErrorCodeConverter.convert(ErrorCodeConverter.java:79)
at net.sf.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:29)
at net.sf.hibernate.persister.AbstractEntityPersister.convert(AbstractEntityPersister.java:1331)
at net.sf.hibernate.persister.EntityPersister.load(EntityPersister.java:416)
at net.sf.hibernate.impl.SessionImpl.doLoad(SessionImpl.java:2131)
at net.sf.hibernate.impl.SessionImpl.doLoadByClass(SessionImpl.java:2001)
at net.sf.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:1963)
at net.sf.hibernate.type.ManyToOneType.resolveIdentifier(ManyToOneType.java:69)
at net.sf.hibernate.type.EntityType.resolveIdentifier(EntityType.java:208)
at net.sf.hibernate.type.EntityType.nullSafeGet(EntityType.java:130)
at net.sf.hibernate.collection.AbstractCollectionPersister.readElement(AbstractCollectionPersister.java:365)
at net.sf.hibernate.collection.Bag.readFrom(Bag.java:75)
at net.sf.hibernate.loader.Loader.readCollectionElement(Loader.java:384)
at net.sf.hibernate.loader.Loader.getRowFromResultSet(Loader.java:240)
at net.sf.hibernate.loader.Loader.doQuery(Loader.java:285)
at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:138)
at net.sf.hibernate.loader.Loader.loadCollection(Loader.java:1020)
at net.sf.hibernate.loader.Loader.loadCollection(Loader.java:995)
at net.sf.hibernate.loader.OneToManyLoader.initialize(OneToManyLoader.java:93)
at net.sf.hibernate.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:288)
at net.sf.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:3315)
at net.sf.hibernate.collection.PersistentCollection.initialize(PersistentCollection.java:195)
at net.sf.hibernate.collection.PersistentCollection.read(PersistentCollection.java:71)
at net.sf.hibernate.collection.Bag.size(Bag.java:232)
at no.test.persistent.Document.toString(Doc.java:216)
at no.test.testing.TestRunner.testRetrieveDocument(TestRunner.java:73)
at no.test.testing.TestRunner.<init>(TestRunner.java:34)
at no.test.testing.TestRunner.main(TestRunner.java:148)
Caused by: java.sql.SQLException: Datastrømmen er allerede lukket
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:179)
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:269)
at oracle.jdbc.dbaccess.DBDataSetImpl.getStreamItem(DBDataSetImpl.java:1571)
at oracle.jdbc.driver.OracleStatement.getBinaryStreamValue(OracleStatement.java:5607)
at oracle.jdbc.driver.OracleResultSetImpl.getBinaryStream(OracleResultSetImpl.java:746)
at oracle.jdbc.driver.OracleResultSet.getBinaryStream(OracleResultSet.java:1662)
at net.sf.hibernate.type.BinaryType.get(BinaryType.java:36)
at net.sf.hibernate.type.NullableType.nullSafeGet(NullableType.java:62)
at net.sf.hibernate.type.NullableType.nullSafeGet(NullableType.java:53)
at net.sf.hibernate.type.AbstractType.hydrate(AbstractType.java:67)
at net.sf.hibernate.loader.Loader.hydrate(Loader.java:690)
at net.sf.hibernate.loader.Loader.loadFromResultSet(Loader.java:631)
at net.sf.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:590)
at net.sf.hibernate.loader.Loader.getRow(Loader.java:505)
at net.sf.hibernate.loader.Loader.getRowFromResultSet(Loader.java:218)
at net.sf.hibernate.loader.Loader.doQuery(Loader.java:285)
at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:138)
at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:941)
at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:961)
at net.sf.hibernate.loader.EntityLoader.load(EntityLoader.java:59)
at net.sf.hibernate.loader.EntityLoader.load(EntityLoader.java:51)
at net.sf.hibernate.persister.EntityPersister.load(EntityPersister.java:413)
... 24 more
Exception in thread "main" net.sf.hibernate.LazyInitializationException: Failed to lazily initialize a collection
at net.sf.hibernate.collection.PersistentCollection.initialize(PersistentCollection.java:201)
at net.sf.hibernate.collection.PersistentCollection.read(PersistentCollection.java:71)
at net.sf.hibernate.collection.Bag.size(Bag.java:232)
at no.test.persistent.Document.toString(Doc.java:216)
at no.test.testing.TestRunner.testRetrieveDocument(TestRunner.java:73)
at no.test.testing.TestRunner.<init>(TestRunner.java:34)
at no.test.testing.TestRunner.main(TestRunner.java:148)
Caused by: net.sf.hibernate.exception.GenericJDBCException: could not load: [no.test.persistent.Revision#no.test.persistent.RevisionPK@b]
at net.sf.hibernate.exception.ErrorCodeConverter.handledNonSpecificException(ErrorCodeConverter.java:90)
at net.sf.hibernate.exception.ErrorCodeConverter.convert(ErrorCodeConverter.java:79)
at net.sf.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:29)
at net.sf.hibernate.persister.AbstractEntityPersister.convert(AbstractEntityPersister.java:1331)
at net.sf.hibernate.persister.EntityPersister.load(EntityPersister.java:416)
at net.sf.hibernate.impl.SessionImpl.doLoad(SessionImpl.java:2131)
at net.sf.hibernate.impl.SessionImpl.doLoadByClass(SessionImpl.java:2001)
at net.sf.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:1963)
at net.sf.hibernate.type.ManyToOneType.resolveIdentifier(ManyToOneType.java:69)
at net.sf.hibernate.type.EntityType.resolveIdentifier(EntityType.java:208)
at net.sf.hibernate.type.EntityType.nullSafeGet(EntityType.java:130)
at net.sf.hibernate.collection.AbstractCollectionPersister.readElement(AbstractCollectionPersister.java:365)
at net.sf.hibernate.collection.Bag.readFrom(Bag.java:75)
at net.sf.hibernate.loader.Loader.readCollectionElement(Loader.java:384)
at net.sf.hibernate.loader.Loader.getRowFromResultSet(Loader.java:240)
at net.sf.hibernate.loader.Loader.doQuery(Loader.java:285)
at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:138)
at net.sf.hibernate.loader.Loader.loadCollection(Loader.java:1020)
at net.sf.hibernate.loader.Loader.loadCollection(Loader.java:995)
at net.sf.hibernate.loader.OneToManyLoader.initialize(OneToManyLoader.java:93)
at net.sf.hibernate.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:288)
at net.sf.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:3315)
at net.sf.hibernate.collection.PersistentCollection.initialize(PersistentCollection.java:195)
... 6 more
Caused by: java.sql.SQLException: Datastrømmen er allerede lukket
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:179)
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:269)
at oracle.jdbc.dbaccess.DBDataSetImpl.getStreamItem(DBDataSetImpl.java:1571)
at oracle.jdbc.driver.OracleStatement.getBinaryStreamValue(OracleStatement.java:5607)
at oracle.jdbc.driver.OracleResultSetImpl.getBinaryStream(OracleResultSetImpl.java:746)
at oracle.jdbc.driver.OracleResultSet.getBinaryStream(OracleResultSet.java:1662)
at net.sf.hibernate.type.BinaryType.get(BinaryType.java:36)
at net.sf.hibernate.type.NullableType.nullSafeGet(NullableType.java:62)
at net.sf.hibernate.type.NullableType.nullSafeGet(NullableType.java:53)
at net.sf.hibernate.type.AbstractType.hydrate(AbstractType.java:67)
at net.sf.hibernate.loader.Loader.hydrate(Loader.java:690)
at net.sf.hibernate.loader.Loader.loadFromResultSet(Loader.java:631)
at net.sf.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:590)
at net.sf.hibernate.loader.Loader.getRow(Loader.java:505)
at net.sf.hibernate.loader.Loader.getRowFromResultSet(Loader.java:218)
at net.sf.hibernate.loader.Loader.doQuery(Loader.java:285)
at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:138)
at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:941)
at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:961)
at net.sf.hibernate.loader.EntityLoader.load(EntityLoader.java:59)
at net.sf.hibernate.loader.EntityLoader.load(EntityLoader.java:51)
at net.sf.hibernate.persister.EntityPersister.load(EntityPersister.java:413)
... 24 more
Name and version of the database you are using:Oracle 10g
The generated SQL (show_sql=true):Code:
select doc0_.ID as ID0_ from DOCUMENT doc0_ where doc0_.ID=?
select revisions0_.DOCUMENT_ID as DOCUMENT2___, revisions0_.REVNUM as REVNUM__, revisions0_.REVNUM as REVNUM0_, revisions0_.DOCUMENT_ID as DOCUMENT2_0_, revisions0_.DESCRIPTION as DESCRIPT3_0_, revisions0_.CREATED_BY as CREATED_BY0_, revisions0_.DATE_CREATED as DATE_CRE5_0_, revisions0_.DOCUMENT as DOCUMENT0_, revisions0_.TAG as TAG0_, revisions0_.DELETED as DELETED0_ from REVISION revisions0_ where revisions0_.DOCUMENT_ID=? order by revisions0_.DATE_CREATED
select revision0_.REVNUM as REVNUM1_, revision0_.DOCUMENT_ID as DOCUMENT2_1_, revision0_.DESCRIPTION as DESCRIPT3_1_, revision0_.CREATED_BY as CREATED_BY1_, revision0_.DATE_CREATED as DATE_CRE5_1_, revision0_.DOCUMENT as DOCUMENT1_, revision0_.TAG as TAG1_, revision0_.DELETED as DELETED1_, doc1_.ID as ID0_ from REVISION revision0_ left outer join DOCUMENT doc1_ on revision0_.DOCUMENT_ID=doc1_.ID where revision0_.REVNUM=? and revision0_.DOCUMENT_ID=?