In the code shown below, in the first session, I try to read a Writer from db, then get the Books of the Writer (a one-to-many association from Writer). There is only one. Then I close my session and open another one, and try to update the detached Writer (with a detached Book hanging off of it) into this new session. Cascading concludes the detached Book is actually transient and ends up inserting a new Book in the DB. Why? I know there is a custom version property handler in Book (its code also shown), but it's there for both Books and Writers, so why is one seen as detached and the other as transient?
Additionally, I also dont understand why the version of Book and Writer is bumped up at commit: When the update was made, a new Book was created (wrongly) and then at commit, the new Book's version was bumped up and so was the Writer's. Is a collection owner's version id bumped up each time the collection's membership increases? Please explain also why the Book's version needs to be bumped up as well.
Thank you for your help: I am trying to understand long-running application transactions that map to several DB transactions,
Sundeep
Hibernate version: 3.1.3
Mapping documents: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated by Elver Store tools on Tue Jul 18 14:44:18 PDT 2006--> <hibernate-mapping> <class entity-name="Book" abstract="false" lazy="false" discriminator-value="Book" table="`BOOK`"> <id type="long"> <generator class="native"/> </id> <discriminator column="DTYPE" type="string"/> <version name="_vn_" access="org.elver.store.hibernate.mapping.property.VersionPropertyHandler"/> <property name="title" type="java.lang.String" lazy="false" column="`title`" not-null="false"/> <property name="pages" type="int" lazy="false" column="`pages`" not-null="false"/> <property name="category" lazy="false" access="org.elver.store.hibernate.mapping.EFeatureAccessor" column="`category`" not-null="false"> <type name="org.elver.store.hibernate.mapping.ENumUserIntegerType"> <param name="enumClass">org.eclipse.example.library.BookCategory</param> </type> </property> <many-to-one name="author" entity-name="Writer" cascade="merge,persist,save-update,lock,refresh" lazy="false" insert="true" update="true" not-null="false"> <column not-null="false" unique="false" name="WRITER_AUTHOR_ID"/> </many-to-one> </class> <class entity-name="Library" abstract="false" lazy="false" discriminator-value="Library" table="`LIBRARY`"> <id type="long"> <generator class="native"/> </id> <discriminator column="DTYPE" type="string"/> <version name="_vn_" access="org.elver.store.hibernate.mapping.property.VersionPropertyHandler"/> <property name="name" type="java.lang.String" lazy="false" column="`name`" not-null="false"/> <list name="writers" lazy="true" cascade="all,delete-orphan"> <key update="true"> <column name="LIBRARY_WRITERS_ID" not-null="false" unique="false"/> </key> <list-index column="LIBRARY_WRITERS_IDX"/> <one-to-many entity-name="Writer"/> </list> <list name="books" lazy="true" cascade="all,delete-orphan"> <key update="true"> <column name="LIBRARY_BOOKS_ID" not-null="false" unique="false"/> </key> <list-index column="LIBRARY_BOOKS_IDX"/> <one-to-many entity-name="Book"/> </list> </class> <class entity-name="Writer" abstract="false" lazy="false" discriminator-value="Writer" table="`WRITER`"> <id type="long"> <generator class="native"/> </id> <discriminator column="DTYPE" type="string"/> <version name="_vn_" access="org.elver.store.hibernate.mapping.property.VersionPropertyHandler"/> <property name="name" type="java.lang.String" lazy="false" column="`name`" not-null="false"/> <list name="books" lazy="true" cascade="merge,persist,save-update,lock,refresh"> <key update="true"> <column name="WRITER_AUTHOR_ID" not-null="false" unique="false"/> </key> <list-index column="WRITER_BOOKS_IDX"/> <one-to-many entity-name="Book"/> </list> </class> </hibernate-mapping>
Code between sessionFactory.openSession() and session.close(): Session sess = hbds.getSession(); Transaction tx = sess.beginTransaction(); List result = sess.createQuery(HQL_GET_WRITER).setString("inputname", "JRR Tolkien").list(); if (result.size()== 0) { System.out.println("No writer found"); System.exit(1); } Writer wr = (Writer) result.get(0); List lst = wr.getBooks(); Book bk = (Book) lst.get(0); tx.commit(); sess.close();
sess = hbds.getSession(); tx = sess.beginTransaction(); sess.update(wr); tx.commit(); sess.close();
org.elver.store.hibernate.mapping.property.VersionPropertyHandler:
public class VersionPropertyHandler implements Getter, Setter, PropertyAccessor { /* (non-Javadoc) * @see org.hibernate.property.PropertyAccessor#getGetter(java.lang.Class, java.lang.String) */ public Getter getGetter(Class theClass, String propertyName) throws PropertyNotFoundException { return this; }
/* (non-Javadoc) * @see org.hibernate.property.PropertyAccessor#getSetter(java.lang.Class, java.lang.String) */ public Setter getSetter(Class theClass, String propertyName) throws PropertyNotFoundException { return this; }
/** * Reads the version from the versioncache */ public Object get(Object owner) throws HibernateException { return IdentifierCacheHandler.getVersion(owner); }
/** * Reads the version from the versioncache */ public Object getForInsert(Object owner, Map mergeMap, SessionImplementor session) throws HibernateException { return IdentifierCacheHandler.getVersion(owner); }
/* (non-Javadoc) * @see org.hibernate.property.Getter#getMethod() */ public Method getMethod() { return null; }
/* (non-Javadoc) * @see org.hibernate.property.Getter#getMethodName() */ public String getMethodName() { return null; }
/** Returns Integer.class */ public Class getReturnType() { return Integer.class; }
/** Sets the version in the internal version cache */ public void set(Object target, Object value, SessionFactoryImplementor factory) throws HibernateException { IdentifierCacheHandler.setVersion(target, value); } }
Name and version of the database you are using: HSQLDB 1.8.0.4
Debug level Hibernate log excerpt: ... (Log excerpt after first session closed, this is second session)
2625 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 4723754063085568 2625 [main] DEBUG org.hibernate.transaction.JDBCTransaction - begin 2625 [main] DEBUG org.hibernate.jdbc.ConnectionManager - opening JDBC connection 2625 [main] DEBUG org.hibernate.connection.DriverManagerConnectionProvider - total checked-out connections: 0 2625 [main] DEBUG org.hibernate.connection.DriverManagerConnectionProvider - using pooled JDBC connection, pool size: 0 2641 [main] DEBUG org.hibernate.transaction.JDBCTransaction - current autocommit status: false 2641 [main] DEBUG org.hibernate.jdbc.JDBCContext - after transaction begin 2641 [main] DEBUG org.hibernate.event.def.DefaultSaveOrUpdateEventListener - updating detached instance 2641 [main] DEBUG org.hibernate.event.def.DefaultSaveOrUpdateEventListener - updating [Writer#1] 2657 [main] DEBUG org.hibernate.event.def.DefaultSaveOrUpdateEventListener - updating [Writer#1] 2657 [main] DEBUG org.hibernate.engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: Writer 2657 [main] DEBUG org.hibernate.engine.Cascade - cascade ACTION_SAVE_UPDATE for collection: Writer.books 2657 [main] DEBUG org.hibernate.engine.CascadingAction - cascading to saveOrUpdate: Book 2657 [main] DEBUG org.hibernate.event.def.AbstractSaveEventListener - transient instance of: Book 2657 [main] DEBUG org.hibernate.event.def.DefaultSaveOrUpdateEventListener - saving transient instance 2657 [main] DEBUG org.hibernate.event.def.AbstractSaveEventListener - saving [Book#<null>] 2657 [main] DEBUG org.hibernate.event.def.AbstractSaveEventListener - executing insertions 2657 [main] DEBUG org.hibernate.engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: Book 2657 [main] DEBUG org.hibernate.engine.CascadingAction - cascading to saveOrUpdate: Writer 2657 [main] DEBUG org.hibernate.event.def.AbstractSaveEventListener - persistent instance of: Writer 2657 [main] DEBUG org.hibernate.event.def.DefaultSaveOrUpdateEventListener - ignoring persistent instance 2657 [main] DEBUG org.hibernate.event.def.DefaultSaveOrUpdateEventListener - object already associated with session: [Writer#1] 2657 [main] DEBUG org.hibernate.engine.Cascade - done processing cascade ACTION_SAVE_UPDATE for: Book 2657 [main] DEBUG org.hibernate.engine.Versioning - using initial version: 0 2657 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Inserting entity: Book (native id) 2657 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Version: 0 2657 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0) 2657 [main] DEBUG org.hibernate.SQL - insert into "BOOK" (_vn_, "title", "pages", "category", WRITER_AUTHOR_ID, econtainer_class, e_container, e_container_featureid, DTYPE, id) values (?, ?, ?, ?, ?, ?, ?, ?, 'Book', null) 2657 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - preparing statement 2657 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Dehydrating entity: [Book#<null>] 2657 [main] DEBUG org.hibernate.type.IntegerType - binding '0' to parameter: 1 2657 [main] DEBUG org.hibernate.type.StringType - binding 'The Hobbit' to parameter: 2 2657 [main] DEBUG org.hibernate.type.IntegerType - binding '305' to parameter: 3 2657 [main] DEBUG org.hibernate.type.LongType - binding '1' to parameter: 5 2657 [main] DEBUG org.hibernate.type.IntegerType - binding '-3' to parameter: 8 2672 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1) 2672 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - closing statement 2672 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0) 2672 [main] DEBUG org.hibernate.SQL - call identity() 2672 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - preparing statement 2672 [main] DEBUG org.hibernate.id.IdentifierGeneratorFactory - Natively generated identity: 2 2672 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1) 2672 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - closing statement 2688 [main] DEBUG org.elver.store.hibernate.mapping.identifier.IdentifierCacheHandler - Setting id: 2 for object org.eclipse.example.library.impl.BookImpl in idcache 2688 [main] DEBUG org.hibernate.engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: Book 2688 [main] DEBUG org.hibernate.engine.Cascade - done processing cascade ACTION_SAVE_UPDATE for: Book 2688 [main] DEBUG org.hibernate.engine.Cascade - done cascade ACTION_SAVE_UPDATE for collection: Writer.books 2688 [main] DEBUG org.hibernate.engine.Cascade - done processing cascade ACTION_SAVE_UPDATE for: Writer 2688 [main] DEBUG org.hibernate.transaction.JDBCTransaction - commit 2688 [main] DEBUG org.hibernate.impl.SessionImpl - automatically flushing session 2688 [main] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - flushing session 2688 [main] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - processing flush-time cascades 2688 [main] DEBUG org.hibernate.engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: Writer 2688 [main] DEBUG org.hibernate.engine.Cascade - cascade ACTION_SAVE_UPDATE for collection: Writer.books 2688 [main] DEBUG org.hibernate.engine.CascadingAction - cascading to saveOrUpdate: Book 2688 [main] DEBUG org.hibernate.event.def.AbstractSaveEventListener - persistent instance of: Book 2688 [main] DEBUG org.hibernate.event.def.DefaultSaveOrUpdateEventListener - ignoring persistent instance 2688 [main] DEBUG org.hibernate.event.def.DefaultSaveOrUpdateEventListener - object already associated with session: [Book#2] 2688 [main] DEBUG org.hibernate.engine.Cascade - done cascade ACTION_SAVE_UPDATE for collection: Writer.books 2688 [main] DEBUG org.hibernate.engine.Cascade - done processing cascade ACTION_SAVE_UPDATE for: Writer 2688 [main] DEBUG org.hibernate.engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: Book 2688 [main] DEBUG org.hibernate.engine.CascadingAction - cascading to saveOrUpdate: Writer 2688 [main] DEBUG org.hibernate.event.def.AbstractSaveEventListener - persistent instance of: Writer 2688 [main] DEBUG org.hibernate.event.def.DefaultSaveOrUpdateEventListener - ignoring persistent instance 2688 [main] DEBUG org.hibernate.event.def.DefaultSaveOrUpdateEventListener - object already associated with session: [Writer#1] 2688 [main] DEBUG org.hibernate.engine.Cascade - done processing cascade ACTION_SAVE_UPDATE for: Book 2688 [main] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - dirty checking collections 2688 [main] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - Flushing entities and processing referenced collections 2688 [main] DEBUG org.hibernate.event.def.DefaultFlushEntityEventListener - Updating entity: [Writer#1] 2688 [main] DEBUG org.hibernate.engine.Versioning - Incrementing: 0 to 1 2703 [main] DEBUG org.hibernate.engine.Collections - Collection found: [Writer.books#1], was: [Writer.books#1] (initialized) 2703 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Book.e_container is dirty 2703 [main] DEBUG org.hibernate.event.def.DefaultFlushEntityEventListener - Updating entity: [Book#2] 2703 [main] DEBUG org.hibernate.engine.Versioning - Incrementing: 0 to 1 2703 [main] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - Processing unreferenced collections 2703 [main] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - Scheduling collection removes/(re)creates/updates 2703 [main] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - Flushed: 0 insertions, 2 updates, 0 deletions to 2 objects 2703 [main] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 1 collections 2703 [main] DEBUG org.hibernate.pretty.Printer - listing entities: 2703 [main] DEBUG org.hibernate.pretty.Printer - org.eclipse.example.library.impl.WriterImpl 2703 [main] DEBUG org.hibernate.pretty.Printer - org.eclipse.example.library.impl.BookImpl 2703 [main] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - executing flush 2703 [main] DEBUG org.hibernate.jdbc.ConnectionManager - registering flush begin 2703 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Updating entity: [Writer#1] 2703 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Existing version: 0 -> New version: 1 2703 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0) 2703 [main] DEBUG org.hibernate.SQL - update "WRITER" set _vn_=?, "name"=?, econtainer_class=?, e_container=?, e_container_featureid=? where id=? and _vn_=? 2703 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - preparing statement 2703 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Dehydrating entity: [Writer#1] 2703 [main] DEBUG org.hibernate.type.IntegerType - binding '1' to parameter: 1 2703 [main] DEBUG org.hibernate.type.StringType - binding 'JRR Tolkien' to parameter: 2 2703 [main] DEBUG org.hibernate.type.IntegerType - binding '-2' to parameter: 5 2703 [main] DEBUG org.hibernate.type.LongType - binding '1' to parameter: 6 2703 [main] DEBUG org.hibernate.type.IntegerType - binding '0' to parameter: 7 2703 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1) 2703 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - closing statement 2703 [main] DEBUG org.elver.store.hibernate.mapping.identifier.IdentifierCacheHandler - Setting version: 1 for object org.eclipse.example.library.impl.WriterImpl in idcache 2703 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Updating entity: [Book#2] 2703 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Existing version: 0 -> New version: 1 2703 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0) 2703 [main] DEBUG org.hibernate.SQL - update "BOOK" set _vn_=?, "title"=?, "pages"=?, "category"=?, WRITER_AUTHOR_ID=?, econtainer_class=?, e_container=?, e_container_featureid=? where id=? and _vn_=? 2703 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - preparing statement 2703 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Dehydrating entity: [Book#2] 2703 [main] DEBUG org.hibernate.type.IntegerType - binding '1' to parameter: 1 2703 [main] DEBUG org.hibernate.type.StringType - binding 'The Hobbit' to parameter: 2 2703 [main] DEBUG org.hibernate.type.IntegerType - binding '305' to parameter: 3 2703 [main] DEBUG org.hibernate.type.LongType - binding '1' to parameter: 5 2703 [main] DEBUG org.hibernate.type.IntegerType - binding '-3' to parameter: 8 2703 [main] DEBUG org.hibernate.type.LongType - binding '2' to parameter: 9 2703 [main] DEBUG org.hibernate.type.IntegerType - binding '0' to parameter: 10 2703 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
|