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.  [ 2 posts ] 
Author Message
 Post subject: session.refresh() and session.load() using pessimistic lock
PostPosted: Wed Sep 08, 2004 4:10 pm 
Newbie

Joined: Thu Aug 12, 2004 10:27 am
Posts: 17
Hibernate version:2.1.6

Mapping documents:
<?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.fabrica.locanet.Product"
table="product"
dynamic-update="false"
dynamic-insert="false"
>

<id
name="id"
column="id"
type="long"
>
<generator class="increment">
</generator>
</id>

<many-to-one
name="category"
class="com.fabrica.locanet.Category"
cascade="none"
outer-join="auto"
update="true"
insert="true"
access="property"
column="categoryId"
not-null="true"
/>

<property
name="name"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="name"
length="50"
not-null="true"
/>

<property
name="salePrice"
type="java.math.BigDecimal"
update="true"
insert="true"
access="property"
column="salePrice"
length="2"
not-null="true"
/>

<property
name="rentalPrice"
type="java.math.BigDecimal"
update="true"
insert="true"
access="property"
column="rentalPrice"
length="2"
not-null="true"
/>

<property
name="saleAmount"
type="int"
update="true"
insert="true"
access="property"
column="saleAmount"
/>

<property
name="created"
type="java.util.Date"
update="true"
insert="true"
access="property"
column="created"
not-null="true"
/>

<property
name="release"
type="boolean"
update="true"
insert="true"
access="property"
column="release"
not-null="true"
/>

<property
name="description"
type="java.lang.String"
update="true"
insert="true"
access="property"
>
<column
name="description"
not-null="true"
sql-type="text"
/>
</property>

<set
name="rentalProducts"
lazy="true"
inverse="true"
cascade="all-delete-orphan"
sort="unsorted"
order-by="id asc"
>

<key
column="productId"
>
</key>

<one-to-many
class="com.fabrica.locanet.RentalProduct"
/>
</set>

<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-Product.xml
containing the additional properties and place it in your merge dir.
-->

<joined-subclass
name="com.fabrica.locanet.Film"
dynamic-update="false"
dynamic-insert="false"
>
<key
column="id"
/>

<property
name="title"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="title"
length="100"
not-null="true"
/>

<property
name="country"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="country"
length="50"
not-null="true"
/>

<property
name="year"
type="int"
update="true"
insert="true"
access="property"
column="year"
not-null="true"
/>

<property
name="runningTime"
type="int"
update="true"
insert="true"
access="property"
column="runningTime"
/>

<set
name="directors"
table="FILM_DIRECTOR"
lazy="true"
inverse="false"
cascade="save-update"
sort="unsorted"
>

<key
column="FILM_ID"
>
</key>

<many-to-many
class="com.fabrica.locanet.Artist"
column="DIRECTOR_ID"
outer-join="auto"
/>

</set>

<set
name="actors"
table="FILM_ACTOR"
lazy="true"
inverse="false"
cascade="save-update"
sort="unsorted"
>

<key
column="FILM_ID"
>
</key>

<many-to-many
class="com.fabrica.locanet.Artist"
column="ACTOR_ID"
outer-join="auto"
/>

</set>

</joined-subclass>

</class>

</hibernate-mapping>


Name and version of the database you are using:postgresql 7.2

Hi,
In my application I lock (using session.refresh() or session.load()) an object, update it and commit the transaction. When running multiple threads I started to read out-of-date data from the object.
Here's my thread's run code:

Code:
public void run(){
   ... //obtain session
   session.beginTransaction();
   session.refresh(product,LockMode.UPGRADE);
   if(product.getAmount()>0){
      product.decreaseAmount();
      session.update(product);
      System.out.println("product updated");
   }
   else{
      System.out.println("product out of stock");
   }
   session.commit();
   session.close();
}


After running this code I noticed I was getting more "product updated" messages than there should be. I tryied to replace session.refresh(..) to session.load(..) but the problem happened again. When I looked at the Hibernate SQL output I found out that hibernate first loads my object data and only after that it locks the object. Please take a look at the SQL code and see what I mean:

Code:
Hibernate: select product0_.id as id1_, case when product0__1_.id is not null then 1 when product0_.id is not null then 0 end as clazz_1_, product0_.categoryId as categoryId1_1_, product0_.name as name1_1_, product0_.salePrice as salePrice1_1_, product0_.rentalPrice as rentalPr5_1_1_, product0_.saleAmount as saleAmount1_1_, product0_.created as created1_1_, product0_.release as release1_1_, product0_.description as descript9_1_1_, product0__1_.title as title2_1_, product0__1_.country as country2_1_, product0__1_.year as year2_1_, product0__1_.runningTime as runningT5_2_1_, category1_.id as id0_, category1_.name as name0_, category1_.parentId as parentId0_ from product product0_ left outer join Film product0__1_ on product0_.id=product0__1_.id left outer join category category1_ on product0_.categoryId=category1_.id where product0_.id=?
Hibernate: select children0_.parentId as parentId__, children0_.id as id__, children0_.id as id0_, children0_.name as name0_, children0_.parentId as parentId0_ from category children0_ where children0_.parentId=? order by children0_.name asc
Hibernate: select id from product where id =? for update


I think that the order of the SQL statements is causing the problem. I think hibernate should lock the object before loading its data.
I solved this issue by locking the object before refreshing it:

Code:
public void run(){
   ... //obtain session
   session.beginTransaction();
   session.lock(product,LockMode.UPGRADE);
   session.refresh(product);
   if(product.getAmount()>0){
      product.decreaseAmount();
      session.update(product);
      System.out.println("product updated");
   }
   else{
      System.out.println("product out of stock");
   }
   session.commit();
   session.close();
}


My question: is this the correct behavior of session.refresh() and session.load()? Is there another way to solve my problem?
My Product class is a generic class so that other classes can inherit from it. For example, I have a Film object that extends Product. Please, take a look at the Product mapping file for more information about this. Do you think inheritance is causing this problem?

Thanks,
Jair Jr


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 08, 2004 8:36 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
In Hibernate 2.1, load(LockMode.UPGRADE) and refresh(LockMode.UPGRADE) do not do what you want if the class has <joined-subclass>es. There were historical reasons for this that no longer apply, and so in Hibernate3 it always takes just one select to refresh/load an object and obtain an upgrade lock.


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