-->
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.  [ 4 posts ] 
Author Message
 Post subject: Stale object has updated version number
PostPosted: Thu Feb 26, 2004 1:11 pm 
Newbie

Joined: Thu Feb 26, 2004 11:53 am
Posts: 2
Hi, I'm using versioned data for optimistic locking in long transactions. I was testing out the locking and found my stale object was having its version number updated but nothing else.

For example:

User object has the following stale properties:

First name = John
Last name = Doe
Version = 0

The database record has the following:

First name = Johnny
Last name = Doe
Version = 1

When I execute the following code with the above stale User object:

Code:

public void saveOrUpdateUser(User user) throws DAOException {
        DAOException error = null;
        Transaction tx = null;
        try {
            Session session =
                HibernateJNDIUtil.getSession(RiverdogProperties.RIVERDOG_AMP);
            tx = session.beginTransaction();
            session.saveOrUpdate(user);
            tx.commit();
        } catch (StaleObjectStateException sose) {
            error = new StaleDataException("Stale data when updating user " + user.getUserName(), sose);
            //user.setVersion(new Long(-1));
        } catch (HibernateException he) {       
            error = new DAOException("Error saving user " + user.getUserName(), he);
        } finally {
            if (error != null) {
                try {
                    if (tx != null) {
                        tx.rollback();
                    }
                } catch (Throwable t) {
                    //nothing to do here...
                }
               
                //docs say to close session if rollback occurs
                HibernateJNDIUtil.closeSession(RiverdogProperties.RIVERDOG_AMP);
               
                logger.error(error);
                throw error;
            }
     }



I get the expected StaleObjectStateException but my stale object looks like this:

First name = John
Last name = Doe
Version = 1

The version number (and only the version number) was updated. Immediately running the method again with the stale object causes the update to succeed which, of course, is not what I want... My commented out fix is above in the StaleObjectStateException catch block. This seems to work (won't allow the update to occur until the user has explicitly retrieved the latest version from the db).

I'm using Hibernate 2.1 with JDK 1.4 and Tomcat 5.0.16 with Oracle 9i.

My mapping file:

Code:

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
    <class  name="com.enterbridge.riverdog.domain.User"
           table="Users"
           dynamic-update="false"
           dynamic-insert="false">

        <id     name="userName"
               column="UserName"
               type="java.lang.String">
            <generator class="assigned"/>
        </id>

        <version   name="version"
                  type="long"
                  column="Version"/>

        <property   name="email"
                  type="java.lang.String"
                  update="true"
                  insert="true"
                  column="Email"/>

        <property   name="password"
                  type="java.lang.String"
                  update="true"
                  insert="true"
                  column="Password"/>

      <idbag    name="roles"
            table="UsersRoles"
            lazy="false">
            
          <collection-id column="ID" type="string">
              <generator class="uuid.hex"/>
          </collection-id>

          <key column="UserName"/>
          <many-to-many    column="RoleName"
                      class="com.enterbridge.riverdog.domain.Role"
                      outer-join="true"/>
      </idbag>

        <property   name="firstName"
                  type="java.lang.String"
                  update="true"
                  insert="true"
                  column="FirstName"/>

        <property   name="lastName"
                  type="java.lang.String"
                  update="true"
                  insert="true"
                  column="LastName"/>

        <property   name="created"
                  type="java.util.Date"
                  update="false"
                  insert="true"
                  column="Created"/>

        <property   name="modified"
                  type="java.util.Date"
                  update="true"
                  insert="true"
                  column="Modified"/>

    </class>

</hibernate-mapping>



Am I doing something wrong or is this a feature/bug in Hibernate?

Thanks,

Matt


Top
 Profile  
 
 Post subject:
PostPosted: Sat Feb 28, 2004 5:40 pm 
Newbie

Joined: Sun Nov 30, 2003 7:24 am
Posts: 11
Well, the Hibernate doc on page 131 says:

Quote:
Don't treat exceptions as recoverable.
This is more of a necessary paractice than a "best" practice. When an exception occurs, roll back the
Transaction and close the Session. If you don't, Hibernate can't guarantee that in-memory state accurately represents persistent state.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Feb 29, 2004 9:59 am 
Newbie

Joined: Thu Feb 26, 2004 11:53 am
Posts: 2
I do rollback the transaction and close the session in my finally block... Unfortunately, rolling back the transaction and closing the session does not seem to effect the object in anyway. I debugged through the Hibernate source and found that Hibernate clones the object's state (the fields that will get updated in the database), updates this state with the next version number, and then writes this state back into the object. Finally, it tries the update and blows up but leaves the updated state in the object. The expected behavior would be StaleObjectStateException with the original state restored...

I guess Hibernate expects you to discard the object and retrieve a fresh instance from the database? Also, I did find specifying select-before-update="true" in the class mapping worked as expected (StaleObjecStateException with no updated state in the object - version number left the same). This is fine but I do wish the same could be accomplished without the additional select...


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 24, 2004 3:40 pm 
Regular
Regular

Joined: Fri Dec 12, 2003 2:09 pm
Posts: 84
Location: San Francisco, USA
matthew_pflueger wrote:
I do rollback the transaction and close the session in my finally block... Unfortunately, rolling back the transaction and closing the session does not seem to effect the object in anyway. I debugged through the Hibernate source and found that Hibernate clones the object's state (the fields that will get updated in the database), updates this state with the next version number, and then writes this state back into the object. Finally, it tries the update and blows up but leaves the updated state in the object. The expected behavior would be StaleObjectStateException with the original state restored...


Hibernate cannot restore the "original state" of the other properties in the object, so in some sense this is more consistent. When a transaction fails and rolls back, you always have to be very careful about what you do with any objects involved... and indeed the best options is usually to discard them.

matthew_pflueger wrote:
Also, I did find specifying select-before-update="true" in the class mapping worked as expected (StaleObjecStateException with no updated state in the object - version number left the same). This is fine but I do wish the same could be accomplished without the additional select...


I agree: if the object is "unchanged", it would be nice if Hibernate does nothing with it. I was thinking that Hibernate could introduce a Mutable interface that allows objects to respond to the inquiry "have you changed since you were loaded?" via an isDirty() method.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 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.