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