-->
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: Optimistic Locking not working
PostPosted: Tue Aug 02, 2005 9:26 pm 
Beginner
Beginner

Joined: Wed Dec 10, 2003 6:58 pm
Posts: 40
Location: Stockholm, Sweden
Hello,

I have a problem with optimistic locking. It is a web application and runs in JBoss 4.0.2 with Hibernate 3 and MySQL 4.1.0.

I have 2 web browsers started. I select the same company from a dropdown list in the 2 browsers. In the browser from which selected after the first I change the name of the company and updates. I check in database and the change is there. I now change the name of the company in the first browser and updates and I get no StaleException which I expected.

The two users reads the same updateVersion, e.g. 1. The second user updates company name and the record gets updateVersion = 2. The first user updates company name of the same db record BUT although the 2nd user changed the updateVersion = 2 and the 1st read updateVersion = 1 no exception is thrown.

What am I doing wrong.

Best regards

Lasse

Hibernate version: 3

Mapping documents:

hibernate.cfg.xml
Code:
<hibernate-configuration>
  <session-factory>
    <property name="connection.datasource">java:/MySqlDS</property>
    <property name="show_sql">true</property>
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.cglib.use_reflection_optimizer">false</property>

    <!-- Mapping files -->
    <mapping resource="Company.hbm.xml"/>
                           
  </session-factory>
</hibernate-configuration>


Company.hbm.xml
Code:
<hibernate-mapping>
<class name="Company"
       table="company"
       optimistic-lock="version">

  <id name="id"
      type="int"
      column="ID"
      unsaved-value="null">
    <generator class="identity"/>
  </id>

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

    <property
        name="name"
        type="java.lang.String"
        column="name"
        not-null="true"
    />
    <property
        name="homePage"
        type="java.lang.String"
        column="homePage"
    />
</class>
</hibernate-mapping>


Code between sessionFactory.openSession() and session.close():
Code:
Transaction tx = HibernateUtil.getSession.beginTransaction();
HibernateUtil.getSession().saveOrUpdate( company );


Then there is a class HibernateFilter from where HibernateUtil.commitTransaction() and HibernateUtil.closeSession() is called.


Full stack trace of any exception that occurs: No exception

Name and version of the database you are using:
MySQL, 4.1.0-alpha-max-debug

The generated SQL (show_sql=true):

Debug level Hibernate log excerpt:


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 02, 2005 9:38 pm 
Beginner
Beginner

Joined: Wed Dec 10, 2003 6:58 pm
Posts: 40
Location: Stockholm, Sweden
The code for HibernateFilter:

Code:
package storage;

import org.apache.commons.logging.*;

import javax.servlet.*;
import java.io.IOException;

public class HibernateFilter implements Filter {

  private static Log log = LogFactory.getLog(HibernateFilter.class);

  public void init(FilterConfig filterConfig) throws ServletException {
    log.info("Servlet filter init, now opening/closing a Session for each request.");
  }

  public void doFilter( ServletRequest request,
                        ServletResponse response,
                        FilterChain chain ) throws IOException, ServletException {

    // There is actually no explicit "opening" of a Session, the
    // first call to HibernateUtil.beginTransaction() in control
    // logic (e.g. use case controller/event handler) will get
    // a fresh Session.
    try {
      chain.doFilter(request, response);

      // Commit any pending database transaction.
      HibernateUtil.commitTransaction();

    } finally {

      // No matter what happens, close the Session.
      HibernateUtil.closeSession();

    }
  }

  public void destroy() {}

}


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 02, 2005 11:31 pm 
Expert
Expert

Joined: Mon Feb 14, 2005 12:32 pm
Posts: 609
Location: Atlanta, GA - USA
Are you sure no exception is thrown ?

Remember, the exception wouldn't occur until the HibernateUtil.commitTransaction(); in the Filter.

Do both updates actually occur ?
What is the version value in the DB when you're done ?

_________________
Preston

Please don't forget to give credit if/when you get helpful information.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 03, 2005 6:13 am 
Beginner
Beginner

Joined: Wed Dec 10, 2003 6:58 pm
Posts: 40
Location: Stockholm, Sweden
I keep watching what happens in the database through a mysql-prompt window. There I can see that both updates of the companys name is performed.

Furthermore, user #2 changes updateVersion to 2. After user#1 has performed its update the updateVersion number is 3.

This is not what I want. When user#2 retrieves a list of existing companies, his update of name has been overwritten by user#1.

Strange, huh?

HibernateUtil.commitTransaction (from caveatEmptor)

Code:
  /**
   * Commit the database transaction.
   */
  public static void commitTransaction() throws InfrastructureException {

    Transaction tx = (Transaction) threadTransaction.get();
    try {
      if ( tx != null && !tx.wasCommitted() && !tx.wasRolledBack() ) {
        log.info("=====================================> Committing database transaction of this thread.");
        tx.commit();
      }
      threadTransaction.set(null);
    }
    catch (HibernateException ex) {
      rollbackTransaction();
      throw new InfrastructureException(ex);
    }
  }



I also changed HibernateFilter.doFilter() this way. No exception seems to be thrown since I don't get any log output.

Code:
  public void doFilter( ServletRequest request,
                        ServletResponse response,
                        FilterChain chain ) throws IOException, ServletException {

    // There is actually no explicit "opening" of a Session, the
    // first call to HibernateUtil.beginTransaction() in control
    // logic (e.g. use case controller/event handler) will get
    // a fresh Session.
    try {
      chain.doFilter(request, response);

      // Commit any pending database transaction.
      HibernateUtil.commitTransaction();

    }
    catch( InfrastructureException ie ) {
      log.info( ie.getMessage() );
    }
    finally {
      // No matter what happens, close the Session.
      HibernateUtil.closeSession();
    }
  }


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 03, 2005 8:05 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 3:00 pm
Posts: 1816
Location: Austin, TX
so what is your processing when a user "updates the company name"? Do you re-load() the Company? Some (psuedo) code might help


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 04, 2005 8:02 am 
Beginner
Beginner

Joined: Wed Dec 10, 2003 6:58 pm
Posts: 40
Location: Stockholm, Sweden
Hi,

I use Struts and at the end of an update action I forward to a jsp page connected to an action which, yes, loads all the companys once more.

My assumption has been that the order of what is happening is the following (but I am not sure):

1) I start the transaction with HibernateUtil.begin()

2) The hibernate-update is done in my DAO-object.

3) After the update logic is done I forward the action to a jsp-page Company.jsp with return ( mapping.findForward( "input" ) );

4) The servlet-filter is executed before the forward is done to Company.jsp. In the servlet filter I call HibernateUtil.commitTransaction() and HibernateUtil.closeSession(). I expected to have the exception thrown in HibernateFilter, but...

5) The actual forward to Company.jsp is done.
In the related Action class the following is done:
Code:
HibernateUtil.beginTransaction();
companies = HibernateUtil.getSession().createQuery( "from Company b order by b.name" ).list();


The list companies is then used to fill the values of a html:select (struts select).


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 04, 2005 8:12 am 
Newbie

Joined: Wed Aug 03, 2005 9:10 am
Posts: 3
Dear Lasse,
Are you sure the version number is written to the form (e.g. in a hidden form field)? What often happens is when the form is posted, you retrieve the persistent object, update it with data from the form, then persist it. Unless the version number is copied from the form to the persistent object, your object will have the latest version number. An alternative strategy is to cache the object in the user's sessions.

Hope this helps, -Jan Voskuil

_________________
Jan Voskuil


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 08, 2005 5:26 am 
Beginner
Beginner

Joined: Wed Dec 10, 2003 6:58 pm
Posts: 40
Location: Stockholm, Sweden
Dear Jan,

You are right. In some way user#1 who makes the last update have the latest updateversion that user#2 (the user that did the first update) created. But, I really can't figure out the reason for this.

I have some trace below. How on earth does the second ActionForm get the new updateversion. I thought that action form objects are independent objects per user session. User#2 makes a reload after updating so that the new company is shown in its browser. But that reload should not affect the action form object of user#1, right?

Code:
User #1 reading
11:06:45,234 INFO  [STDOUT] Hibernate: select company0_.ID as ID0_, company0_.updateVersion as updateVe2_1_0_, company0_.name as name1_0_, company0_.homePage as homePage1_0_ from company company0_ where company0_.ID=?
11:06:45,265 INFO  [CompanyAction] TMPTMP ===============> read updateversion = 17
11:06:45,265 INFO  [STDOUT] ======>>>>>>> CompanyActionForm.setUpdateVersion. updateVersion = 17
11:06:45,265 INFO  [PropertyMessageResources] Initializing, config='com.fgm.web.menu.displayer.DisplayerStrings', returnNull=true
11:06:45,281 INFO  [HibernateFilter] TMPTMP ====================================> Before HibernateUtil.commitTransaction
11:06:45,281 INFO  [HibernateFilter] TMPTMP ====================================> After HibernateUtil.commitTransaction
11:06:45,281 INFO  [HibernateFilter] TMPTMP ====================================> About to close session

User #2 reading
11:06:52,390 INFO  [STDOUT] Hibernate: select company0_.ID as ID0_, company0_.updateVersion as updateVe2_1_0_, company0_.name as name1_0_, company0_.homePage as homePage1_0_ from company company0_ where company0_.ID=?
11:06:52,406 INFO  [CompanyAction] TMPTMP ===============> read updateversion = 17
11:06:52,406 INFO  [STDOUT] ======>>>>>>> CompanyActionForm.setUpdateVersion. updateVersion = 17
11:06:52,406 INFO  [PropertyMessageResources] Initializing, config='com.fgm.web.menu.displayer.DisplayerStrings', returnNull=true
11:06:52,421 INFO  [HibernateFilter] TMPTMP ====================================> Before HibernateUtil.commitTransaction
11:06:52,421 INFO  [HibernateFilter] TMPTMP ====================================> After HibernateUtil.commitTransaction
11:06:52,421 INFO  [HibernateFilter] TMPTMP ====================================> About to close session


User #2 updating
11:08:27,406 INFO  [STDOUT] ======>>>>>>> CompanyActionForm.getUpdateVersion. updateVersion = 17
11:08:27,406 INFO  [STDOUT] ======>>>>>>> CompanyActionForm.getUpdateVersion. updateVersion = 17
11:08:27,406 INFO  [CompanyAction] ==========> update(): CompanyActionForm.updateVersion17
11:08:27,406 INFO  [CompanyDAOImpl] TMPTMP ===============> about to update. updateversion = 17
11:08:27,406 INFO  [STDOUT] Hibernate: update company set updateVersion=?, name=?, homePage=? where ID=? and updateVersion=?
11:08:27,499 INFO  [STDOUT] Hibernate: select company0_.ID as ID, company0_.updateVersion as updateVe2_1_, company0_.name as name1_, company0_.homePage as homePage1_ from company company0_ order by company0_.name
11:08:27,546 INFO  [CompanyAction] ===============> buildCompanySelect. company.getUpdateVersion() = 24
11:08:27,546 INFO  [STDOUT] ======>>>>>>> CompanyActionForm.setUpdateVersion. updateVersion = 24
11:08:27,546 INFO  [STDOUT] ======>>>>>>> CompanyActionForm.setUpdateVersion. updateVersion = 18
11:08:27,562 INFO  [PropertyMessageResources] Initializing, config='com.fgm.web.menu.displayer.DisplayerStrings', returnNull=true
11:08:27,562 INFO  [HibernateFilter] TMPTMP ====================================> Before HibernateUtil.commitTransaction
11:08:27,562 INFO  [HibernateFilter] TMPTMP ====================================> After HibernateUtil.commitTransaction
11:08:27,562 INFO  [HibernateFilter] TMPTMP ====================================> About to close session

User #1 updating
11:10:35,062 INFO  [STDOUT] ======>>>>>>> CompanyActionForm.getUpdateVersion. updateVersion = 18
11:10:35,062 INFO  [STDOUT] ======>>>>>>> CompanyActionForm.getUpdateVersion. updateVersion = 18
11:10:35,062 INFO  [CompanyAction] ==========> update(): CompanyActionForm.updateVersion18
11:10:35,062 INFO  [CompanyDAOImpl] TMPTMP ===============> about to update. updateversion = 18
11:10:35,062 INFO  [STDOUT] Hibernate: update company set updateVersion=?, name=?, homePage=? where ID=? and updateVersion=?
11:10:35,109 INFO  [STDOUT] Hibernate: select company0_.ID as ID, company0_.updateVersion as updateVe2_1_, company0_.name as name1_, company0_.homePage as homePage1_ from company company0_ order by company0_.name
11:10:35,124 INFO  [CompanyAction] ===============> buildCompanySelect. company.getUpdateVersion() = 24
11:10:35,124 INFO  [STDOUT] ======>>>>>>> CompanyActionForm.setUpdateVersion. updateVersion = 24
11:10:35,140 INFO  [STDOUT] ======>>>>>>> CompanyActionForm.setUpdateVersion. updateVersion = 19
11:10:35,140 INFO  [PropertyMessageResources] Initializing, config='com.fgm.web.menu.displayer.DisplayerStrings', returnNull=true
11:10:35,140 INFO  [HibernateFilter] TMPTMP ====================================> Before HibernateUtil.commitTransaction
11:10:35,140 INFO  [HibernateFilter] TMPTMP ====================================> After HibernateUtil.commitTransaction
11:10:35,140 INFO  [HibernateFilter] TMPTMP ====================================> About to close session


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 08, 2005 6:39 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 3:00 pm
Posts: 1816
Location: Austin, TX
because at some point you reload it. you need to keep a reference to that original around between the time the user initially views the versioned entity and when they post their changes (presumably in http-session).


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 08, 2005 10:46 am 
Beginner
Beginner

Joined: Wed Dec 10, 2003 6:58 pm
Posts: 40
Location: Stockholm, Sweden
1)When User#1 reads the list of companies it reads updateVersion # 17. The last thing that happens with the company for User#1 is in the ActionForm object:

Code:
11:06:45,265 INFO  [STDOUT] ======>>>>>>> CompanyActionForm.setUpdateVersion. updateVersion = 17


This is done when User#1 has selected a company from a dropdown list. After that User#1 does nothing.

2)User#2 then selects the same company, changes its name and then saves it.

3)Now User#1 changes the name of the same company that User#2 changed in 2) above. This is the first thing User#1 does after 1) above. The first thing that happens in CompanyAction is that I create a new Company object and populates it from the ActionForm object. After the update is performed.

Code:
Company company = new Company();
company.setUpdateVersion( Long.parseLong( ((CompanyActionForm)form).getUpdateVersion() ) );
log.info( "==========> update(): CompanyActionForm.updateVersion" + ((CompanyActionForm)form).getUpdateVersion() );

//.. setting other fields as well
HibernateUtil.beginTransaction();
((CompanyDAOInterface)getDAO( Constants.COMPANY_DAO_KEY )).update( company );


trace info:
Code:
11:10:35,062 INFO  [STDOUT] ======>>>>>>> CompanyActionForm.getUpdateVersion. updateVersion = 18


I don't do any loading of objects for User#1 myself. I assumed, maybe incorrectly, that different sessions have their own ActionForm objects ( I am aware of that this is a Struts issue ) and therefore their own values. For example, the company name that User#1 entered is updated in database. Shouldn't the name of the company be loaded as well as the update version then?

Best regards

Lasse


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 09, 2005 4:51 am 
Beginner
Beginner

Joined: Wed Dec 10, 2003 6:58 pm
Posts: 40
Location: Stockholm, Sweden
steve wrote:
because at some point you reload it.


When the second update is executed values are selected from the ActionForm object which I assume belongs to a specific Http-session, i.e. different for the 2 users.

steve wrote:
you need to keep a reference to that original around between the time the user initially views the versioned entity and when they post their changes (presumably in http-session).


The original values are stored in the ActionForm object which is related to a specific http-session, right?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 09, 2005 6:35 am 
Beginner
Beginner

Joined: Wed Dec 10, 2003 6:58 pm
Posts: 40
Location: Stockholm, Sweden
I think I found something of interest.

It seems to be the same HttpSession due to how I opened the different browsers. I think I did the mistake of opening the second IE with Ctrl+N. Nothing else wrong with my code as it seems.

Best regards

Lasse


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 09, 2005 6:36 am 
Beginner
Beginner

Joined: Wed Dec 10, 2003 6:58 pm
Posts: 40
Location: Stockholm, Sweden
When I opened the second Internet Explorer via Windows-start=>Run=>iexplore .. then it worked.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 09, 2005 12:47 pm 
Beginner
Beginner

Joined: Wed Dec 10, 2003 6:58 pm
Posts: 40
Location: Stockholm, Sweden
Why didn't u tell me this ;-)


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.