-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 14 posts ] 
Author Message
 Post subject: Update done without asking !?
PostPosted: Tue Dec 02, 2003 4:22 pm 
Newbie

Joined: Tue Aug 26, 2003 9:52 am
Posts: 15
Hello Everyone,

I know I must be wrong but please tell me what I missed.

At some point the transaction is commtted, flush gets invoked.

An entity is detected to be dirty (which is true) then updated. The problem is that neither save nor update nor saveOrUpdate was called on that entity (doubled check with debugger).

Any clue ?

Thanks alot for your help.

Alain.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 02, 2003 4:31 pm 
Proxool Developer
Proxool Developer

Joined: Tue Aug 26, 2003 10:42 am
Posts: 373
Location: Belgium
Hey ??
That's one of the most fantastic features of Hibernate - checkout the following PowerPoint presentation: http://www.hibernate.org/hib_docs/online/jaoo_presentation/HibernateJAOO.ppt

(once an object is loaded into/by the session, you don't have to tell Hibernate to persist the changes - it will do it by magic, at last when the transaction is committed - sometimes before when required)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 02, 2003 4:41 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
This is called "automatic dirty checking". Each object that is associated with the current Session (through fetch, update or lock) is automatically checked for state changes. All changes are then flushed to the database and committed at the end of each transaction (which one Session can have many).

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 04, 2003 3:23 pm 
Newbie

Joined: Tue Aug 26, 2003 9:52 am
Posts: 15
Huhh this is dangerous... Is there a way to disable that behavior ??

Thanks guys.

Alain .


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 04, 2003 3:31 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
This is how Hibernate (and JDO and many others) works, with transactional objects and automatic dirty checking. You can turn off "update" and "insert" for properties though. If you want non-automatic behavior, don't use a full ORM tool, but a more simple abstraction layer on top of SQL.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 04, 2003 4:21 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
alkr wrote:
Huhh this is dangerous... Is there a way to disable that behavior ??

Thanks guys.

Alain .


Call rollback() ?

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject: update immediately after insert
PostPosted: Fri Jan 09, 2004 6:28 pm 
Newbie

Joined: Thu Jan 08, 2004 6:54 pm
Posts: 8
Hi! I think I am experiencing this as well. I have a Contact and Address in a one-to-many relationship. When I insert the Contact (cascades to insert Address too) Hibernate immediately performs an update after the inserts within the same transaction!

My Log:

Hibernate: insert into Contact (version, email, firstName, lastName, id) values (?, ?, ?, ?, ?)
Hibernate: insert into Address (version, city, state, street1, street2, zip, contactId, typeCode, id) values (?, ?, ?, ?, ?, ?, ?, 1, ?)
Hibernate: update Contact set version=?, email=?, firstName=?, lastName=? where id=? and version=?
Hibernate: update Address set contactId=? where id=?

In my debugger, SessionImpl.flushEntity() calls isUpdateNecessary() which determines that 'yes' an update is necessary. It seems like a waste to me.

If this is a different problem, please advise on how to prevent updating immediately after inserting.


Top
 Profile  
 
 Post subject: Re: update immediately after insert
PostPosted: Sun Jan 11, 2004 11:51 am 
Proxool Developer
Proxool Developer

Joined: Tue Aug 26, 2003 10:42 am
Posts: 373
Location: Belgium
troutman wrote:
Hi! I think I am experiencing this as well. I have a Contact and Address in a one-to-many relationship. When I insert the Contact (cascades to insert Address too) Hibernate immediately performs an update after the inserts within the same transaction!

My Log:

Hibernate: insert into Contact (version, email, firstName, lastName, id) values (?, ?, ?, ?, ?)
Hibernate: insert into Address (version, city, state, street1, street2, zip, contactId, typeCode, id) values (?, ?, ?, ?, ?, ?, ?, 1, ?)
Hibernate: update Contact set version=?, email=?, firstName=?, lastName=? where id=? and version=?
Hibernate: update Address set contactId=? where id=?

In my debugger, SessionImpl.flushEntity() calls isUpdateNecessary() which determines that 'yes' an update is necessary. It seems like a waste to me.

If this is a different problem, please advise on how to prevent updating immediately after inserting.


Let me guess what your programs does:
1/ Create a new Contact and tell Hibernate to persist it;
2/ Then create a new Address and add it to the Contact.address list

This will lead to the following Hibernate actions:
1/ Insert a new Contact record (because of point 1 above);
2/ Insert a new Address record - Hibernate does it because it found a transient instance in the Contact.adress list;
3/ Your Contact instance seems to have a version attribute that needs to be updated - a new address has been added to the list, so the contact instance is not the same as before. This leads to the third update sql statement you found in the log;
4/ Finally, the address is linked to the contact - this is the latest update statement you found...

Hope this helps you to understand what Hibernate is doing.


Top
 Profile  
 
 Post subject: updates immediately after insert in same TXN
PostPosted: Wed Jan 14, 2004 1:38 pm 
Newbie

Joined: Thu Jan 08, 2004 6:54 pm
Posts: 8
I've followed my code through the debugger and tracked down some areas that I'd like feedback on from a Hibernate implementation viewpoint. First of all, let me give specifics on my code and configuration.

I have a one-to-many association with Contact-to-Addresses.

ContactBO.hbm.xml association configuration:

Code:
<bag
            name="addresses"
            table="Address"
            lazy="true"
            inverse="false"
            cascade="all"
>
<key
            column="contactId"
/>

<one-to-many
           class="commerce.model.contact.AddressBO"
/>
</bag>



Address.hbm.xml's association back to ContactBO:

Code:
<many-to-one
            name="contact"
            class="commerce.model.contact.ContactBO"
            cascade="none"
            outer-join="auto"
            update="true"
            insert="true"
            column="contactId"
            not-null="true"
/>




Here is my code in a nutshell:
Code:
/**
    * This will do 2 inserts and then immediately call 2 updates
    * in the same transaction.
    *
    * Note: Junit setup() initializes Configuration, SessionFactory, etc.
    * and teardown() closes everything up. 
    *
    * Hibernate seems to do the following to cause the unwanted updates:
    * 1. Replaces ArrayList with Bag to cause ContactBO to update
    * 2. Adds 'contact-addresses' association to the collectionCreation
    * list, updating the BillingAddressBO as well.
    *
    * @throws Exception
    */
   public void testContactInsert() throws Exception {
      Transaction txn = null;
      try {
         ContactBO contact = new ContactBO();
         
         // since emails have to be unique, generate
         // one per test based on the time
         long time = System.currentTimeMillis();
         contact.setEmail(time+"@test.com");
         contact.setFirstName("JUFirst");
         contact.setLastName("JULast");

         BillingAddressBO billingAddress = new BillingAddressBO();
         
         billingAddress.setCity("JUSomewhereCity");
         billingAddress.setState("CO");
         billingAddress.setStreet1("Street1");
         billingAddress.setStreet2("Street2");
         billingAddress.setZip("80211");

         //associate Contact and BillingAddress
         contact.setAddresses(new ArrayList(1));
         List addresses = contact.getAddresses();
         addresses.add(billingAddress);
         
         billingAddress.setContact(contact);

         txn = session.beginTransaction();
         
         Long cntctId = (Long)session.save(contact);
         
         txn.commit();
      } catch (MappingException me) {
         throw me;
      } catch (HibernateException he) {
         throw he;
      } finally {
         // if txn not committed, rollback here
         checkForRollback(txn);
      }
   }


session.save(contact) adds two ScheduledInsertions.
txn.commit() adds a Scheduled Update and a collectionCreation entry.

So, it ends up with 2 inserts and 2 updates. Here is the log:

2004-01-13 16:13:30,099 INFO hibernate.impl.SessionFactoryObjectFactory -> no JNDI name configured
Hibernate: insert into Contact (version, email, firstName, lastName, id) values (?, ?, ?, ?, ?)
2004-01-13 17:08:53,447 DEBUG hibernate.type.LongType -> binding '0' to parameter: 1
2004-01-13 17:08:53,447 DEBUG hibernate.type.StringType -> binding '1074035610189@test.com' to parameter: 2
2004-01-13 17:08:53,447 DEBUG hibernate.type.StringType -> binding 'JUFirst' to parameter: 3
2004-01-13 17:08:53,447 DEBUG hibernate.type.StringType -> binding 'JULast' to parameter: 4
2004-01-13 17:08:53,447 DEBUG hibernate.type.LongType -> binding '25' to parameter: 5
Hibernate: insert into Address (version, city, state, street1, street2, zip, contactId, typeCode, id) values (?, ?, ?, ?, ?, ?, ?, 1, ?)
2004-01-13 17:08:57,533 DEBUG hibernate.type.LongType -> binding '0' to parameter: 1
2004-01-13 17:08:57,533 DEBUG hibernate.type.StringType -> binding 'JUSomewhereCity' to parameter: 2
2004-01-13 17:08:57,533 DEBUG hibernate.type.StringType -> binding 'CO' to parameter: 3
2004-01-13 17:08:57,533 DEBUG hibernate.type.StringType -> binding 'Street1' to parameter: 4
2004-01-13 17:08:57,533 DEBUG hibernate.type.StringType -> binding 'Street2' to parameter: 5
2004-01-13 17:08:57,533 DEBUG hibernate.type.StringType -> binding '80211' to parameter: 6
2004-01-13 17:08:57,533 DEBUG hibernate.type.LongType -> binding '25' to parameter: 7
2004-01-13 17:08:57,543 DEBUG hibernate.type.LongType -> binding '23' to parameter: 8
Hibernate: update Contact set version=? where id=? and version=?
2004-01-13 17:10:02,086 DEBUG hibernate.type.LongType -> binding '1' to parameter: 1
2004-01-13 17:10:02,096 DEBUG hibernate.type.LongType -> binding '25' to parameter: 2
2004-01-13 17:10:02,096 DEBUG hibernate.type.LongType -> binding '0' to parameter: 3
Hibernate: update Address set contactId=? where id=?
2004-01-13 17:12:05,664 DEBUG hibernate.type.LongType -> binding '25' to parameter: 1
2004-01-13 17:12:05,664 DEBUG hibernate.type.LongType -> binding '23' to parameter: 2

Questions/Observations from my debugging session:

1. Have I configured something incorrectly in my hbm.xml's? If so, easy fix! What should I be doing?

2. When the entities are scheduled for insertion, their status is set from SAVING to LOADED. Seems to me like they should be in the process of LOADING until the SQL is commited. Only after txn.commit() is successful, would they become LOADED. Is there a state transition diagram for entities that I could look at for a better understanding?

3. The logs indicate the association between ContactBO and Address is done in the insert statement (e.g., Address FK contactId = 25). So, the extra update statement inside the same txn is unecessary. I think Hibernate has the knowledge to know that duplicate insert and update statements for the association are happening the same txn (therefore they are unecessary). It just needs to apply the knowledge somewhere. This is where I'm at a loss...

pseudo-code during txn.commit() somewhere down the line...

Code:
if (session.isCurrentTransaction=true && associationAlreadyEstablishedOnInsert) {
   // skip additional update of collection
   someCollection.docreate = false;
}


Or, maybe something looking at the entitys' statuses could be used?

4. txn.commit() eventually calls the ContactBO


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 14, 2004 1:47 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Read http://www.hibernate.org/Documentation/InsideExplanationOfInverseTrue

_________________
Emmanuel


Top
 Profile  
 
 Post subject: updates immediately after insert in same TXN
PostPosted: Wed Jan 14, 2004 2:30 pm 
Newbie

Joined: Thu Jan 08, 2004 6:54 pm
Posts: 8
From the tutorial, I changed Contact's association declaration to have inverse=true.

Code:
<bag
            name="addresses"
            table="Address"
            lazy="true"
            inverse="true"
            cascade="all"
>
              <key  column="contactId"
              />
              <one-to-many class="commerce.model.contact.AddressBO"
              />
</bag>


The log looks like this:

>>>> BEGIN INSERTING CONTACT AND BILLING ADDRESS
2004-01-14 11:16:15,601 DEBUG hibernate.impl.SessionImpl -> saving [commerce.model.contact.ContactBO#31]
2004-01-14 11:16:15,621 DEBUG hibernate.impl.SessionImpl -> saveOrUpdate() unsaved instance
2004-01-14 11:16:15,621 DEBUG hibernate.impl.SessionImpl -> saving [commerce.model.contact.BillingAddressBO#29]
2004-01-14 11:16:15,621 DEBUG hibernate.impl.SessionImpl -> flushing session
2004-01-14 11:16:15,621 DEBUG hibernate.impl.SessionImpl -> saveOrUpdate() persistent instance
2004-01-14 11:16:15,621 DEBUG hibernate.impl.SessionImpl -> Flushing entities and processing referenced collections
2004-01-14 11:16:15,631 DEBUG hibernate.impl.SessionImpl -> Updating entity: [commerce.model.contact.ContactBO#31]
2004-01-14 11:16:15,641 DEBUG hibernate.impl.SessionImpl -> Collection found: [commerce.model.contact.ContactBO.addresses#31], was: [<unreferenced>]
2004-01-14 11:16:15,641 DEBUG hibernate.impl.SessionImpl -> Processing unreferenced collections
2004-01-14 11:16:15,641 DEBUG hibernate.impl.SessionImpl -> Scheduling collection removes/(re)creates/updates
2004-01-14 11:16:15,641 DEBUG hibernate.impl.SessionImpl -> Flushed: 2 insertions, 1 updates, 0 deletions to 2 objects
2004-01-14 11:16:15,641 DEBUG hibernate.impl.SessionImpl -> Flushed: 1 (re)creations, 0 updates, 0 removals to 1 collections
2004-01-14 11:16:15,641 DEBUG hibernate.impl.SessionImpl -> executing flush
Hibernate: insert into Contact (version, email, firstName, lastName, id) values (?, ?, ?, ?, ?)
2004-01-14 11:16:15,651 DEBUG hibernate.type.LongType -> binding '0' to parameter: 1
2004-01-14 11:16:15,651 DEBUG hibernate.type.StringType -> binding '1074104175551@test.com' to parameter: 2
2004-01-14 11:16:15,651 DEBUG hibernate.type.StringType -> binding 'JUFirst' to parameter: 3
2004-01-14 11:16:15,651 DEBUG hibernate.type.StringType -> binding 'JULast' to parameter: 4
2004-01-14 11:16:15,651 DEBUG hibernate.type.LongType -> binding '31' to parameter: 5
Hibernate: insert into Address (version, city, state, street1, street2, zip, contactId, typeCode, id) values (?, ?, ?, ?, ?, ?, ?, 1, ?)
2004-01-14 11:16:15,651 DEBUG hibernate.type.LongType -> binding '0' to parameter: 1
2004-01-14 11:16:15,651 DEBUG hibernate.type.StringType -> binding 'JUSomewhereCity' to parameter: 2
2004-01-14 11:16:15,651 DEBUG hibernate.type.StringType -> binding 'CO' to parameter: 3
2004-01-14 11:16:15,651 DEBUG hibernate.type.StringType -> binding 'Street1' to parameter: 4
2004-01-14 11:16:15,651 DEBUG hibernate.type.StringType -> binding 'Street2' to parameter: 5
2004-01-14 11:16:15,651 DEBUG hibernate.type.StringType -> binding '80211' to parameter: 6
2004-01-14 11:16:15,661 DEBUG hibernate.type.LongType -> binding '31' to parameter: 7
2004-01-14 11:16:15,661 DEBUG hibernate.type.LongType -> binding '29' to parameter: 8
Hibernate: update Contact set version=? where id=? and version=? <<-- not necessary in same txn
2004-01-14 11:16:15,661 DEBUG hibernate.type.LongType -> binding '1' to parameter: 1
2004-01-14 11:16:15,661 DEBUG hibernate.type.LongType -> binding '31' to parameter: 2
2004-01-14 11:16:15,661 DEBUG hibernate.type.LongType -> binding '0' to parameter: 3
2004-01-14 11:16:15,661 DEBUG hibernate.impl.SessionImpl -> post flush
2004-01-14 11:16:15,661 DEBUG hibernate.impl.SessionImpl -> transaction completion
>>>> DONE INSERTING CONTACT AND BILLING ADDRESS
2004-01-14 11:16:15,661 DEBUG hibernate.impl.SessionImpl -> closing session
2004-01-14 11:16:15,661 DEBUG hibernate.impl.SessionImpl -> disconnecting session
2004-01-14 11:16:15,661 DEBUG hibernate.impl.SessionImpl -> transaction completion


It looks like the inverse=true resolved the second update of the Address table (e.g., no more Hibernate: update Address set contactId=? where id=?), but the Contact is still getting updated because the ArrayList is changed to a Bag (see #4 in my previous post). This isn't necessary. Anyway to remove it too?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 14, 2004 2:39 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
Yes - don't change to an array list!

do a .clear() and do add()'s to the set in set.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 14, 2004 2:40 pm 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
That should not really make a difference, he is using a newly created object and calling save() ...


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 14, 2004 2:42 pm 
Newbie

Joined: Thu Jan 08, 2004 6:54 pm
Posts: 8
I'm sorry, but I thought Hibernate changed from ArrayList to Bag under-the-covers. I'm unclear on how using a Set instead of Bag and invoking .clear() and .add() will achieve different behavior inside Hibernate. Can you elaborate or point me to more docs like the inverse tutorial?

tx


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 14 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.