-->
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.  [ 17 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: rollback probs and other
PostPosted: Sat Oct 01, 2005 1:42 pm 
Newbie

Joined: Wed Aug 31, 2005 4:32 pm
Posts: 13
Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp

Hibernate version:3.0

Name and version of the database you are using: MySQL 4.1.14 (InnoDB Engine)

Hi, I'm a relatively new hibernate user so it's possible i'm doing
something wrong - sorry for that.

I have several probs with hibernate:

(1) a rollback probem

I need to save objects with unique names and the names should follow a naming rule,
something like fname_[day_of_year]_[i], where [i] is sequental, starting at 1 every new
day. I work in a concurrent environment so I use the following method to store names:

1. I declared the property as an unique key in a table
<property name="fname" unique="true" column="FNAME" />

2. as several process can access the same db at the same time i use the following
technique to ensure uniqueness of the field and to avoid db locks:

tx = null;
i = 1;
while(true) {
try {
tx = new Tx();
obj.fname = getNextName(i++);
session.save(obj);
tx.commit();
break;
} catch(HibernateExcpetion) {
if(tx) {
tx.rollback();
// session.evict(obj);
}
}
}

this code works only for the first object. the problem is that hibernate doesn't
evict object from it's cache/queues when transaction fails (even after a rollback), and next time i try to commit()
it fails, as object(s) with an invalid field value is still there (in the insert queue).
But another problem is that uncommenting the evict() line doesn't help, as after that inalid
object(s) is still in sesson.actionQueue.insertions. Is it so by design and any ideas/suggestions
about how should i implement my case?

(2) polymorphical select problem:

i use table per-subclass method

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="controller.dto.SupplierPostDTO" table="SUPPLIERPOSTS">
<id name="id" type="int" column="id">
<generator class="hilo">
<param name="table">supplierposts_dto_hi_value</param>
<param name="column">supplierposts_dto_next_value</param>
<param name="max_lo">100</param>
</generator>
</id>
<discriminator column="POST_TYPE" type="string"/>

<many-to-one name="supplier" lazy="false" class="controller.dto.SupplierDTO" column="SUPPLIER_ID"/>

<set name="instances" lazy="false" table="SUPPLIER_POST_INSTANCES">
<key column="SUPPLIER_POST_ID"/>
<many-to-many column="INSTANCE_ID" class="controller.dto.InstanceDTO"/>
</set>

<subclass name="controller.dto.OttoSupplierPostDTO" discriminator-value="controller.dto.OttoSupplierPostDTO">
<join table="OTTO_SUPPLIERPOSTS">
<key column="id"/>
<property name="filename" unique="true" column="FILENAME" />
<property name="message" column="MESSAGE" />
</join>
</subclass>

</class>
</hibernate-mapping>

and do the following query:

SELECT {s.*} FROM supplierposts s

here's what hibernate generates:

Hibernate: SELECT s.id as id0_, s.SUPPLIER_ID as SUPPLIER3_10_0_, s_1_.FILENAME as FILENAME12_0_, s_1_.MESSAGE as MESSAGE12_0_, s.POST_TYPE as POST2_0_ FROM supplierposts s

of course there's no 's_1_' table/alias defined

(3) you probably noticed lazy = 'false' in object description

this is due to another problem: I need use serialization and when load-on-demand is enabled, it
(java serialization code) serializes those wrappers instead of real referenced objects. In fact I think it's
a java problem but wonder maybe you can comment this.

Great Thanks in advance
Vladimir


Top
 Profile  
 
 Post subject:
PostPosted: Sat Oct 01, 2005 6:29 pm 
Senior
Senior

Joined: Wed Jul 13, 2005 4:31 pm
Posts: 142
Location: Seattle, WA
I'm not sure what the Tx class u are using is?

Normally the transaction I use comes from the session...
org.hibernate.Transaction transaction = session.beginTransaction();

Then, later do rollback() or commit() on the transaction object


Top
 Profile  
 
 Post subject:
PostPosted: Sat Oct 01, 2005 10:11 pm 
Expert
Expert

Joined: Sat Jun 12, 2004 4:49 pm
Posts: 915
Vladimir (ili Vladimire),
Your code is incorrect
tx = null;
i = 1;
while(true) {
try {
tx = new Tx();
obj.fname = getNextName(i++);
session.save(obj);
tx.commit();
break;
} catch(HibernateExcpetion) {
if(tx) {
tx.rollback();
// session.evict(obj);
}
}

line obj.fname = getNextName(i++);session.save(obj); isn't correct
You try save same object more times
you can make like this :

obj = new YourObject();
obj.fname=getNextName(i++);
.. populate another properties of obj
session.save(obj);


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 02, 2005 2:35 am 
Newbie

Joined: Wed Aug 31, 2005 4:32 pm
Posts: 13
anar wrote:
I'm not sure what the Tx class u are using is?

Normally the transaction I use comes from the session...
org.hibernate.Transaction transaction = session.beginTransaction();

Then, later do rollback() or commit() on the transaction object


yes this is exactly the session.Transaction() I just was in a hurry and shortened that. Sorry for uncrealance.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 02, 2005 2:40 am 
Newbie

Joined: Wed Aug 31, 2005 4:32 pm
Posts: 13
snpesnpe wrote:
Vladimir (ili Vladimire),
Your code is incorrect
tx = null;
i = 1;
while(true) {
try {
tx = new Tx();
obj.fname = getNextName(i++);
session.save(obj);
tx.commit();
break;
} catch(HibernateExcpetion) {
if(tx) {
tx.rollback();
// session.evict(obj);
}
}

line obj.fname = getNextName(i++);session.save(obj); isn't correct
You try save same object more times
you can make like this :

obj = new YourObject();
obj.fname=getNextName(i++);
.. populate another properties of obj
session.save(obj);


No I try each object once - as soon as it is saved and assigned and id I commit and break. Otherwise it breaks a database constraint and cannot be saved. And the behaviour described by me happens regardless or what strategy I use - either I re-use object or ccreate a new instance for each try. The problem is that EVEN AFTER ROLLBACK INVALID OBJECT IS STILL PRESENT IN HIBENATE ACTION QUEUE.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 02, 2005 6:57 am 
Newbie

Joined: Sat Jul 23, 2005 8:31 am
Posts: 18
Quote:
If the Session throws an exception (including any SQLException), you should immediately rollback the database transaction, call Session.close() and discard the Session instance. Certain methods of Session will not leave the session in a consistent state.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 02, 2005 8:24 am 
Newbie

Joined: Wed Aug 31, 2005 4:32 pm
Posts: 13
chrigi wrote:
Quote:
If the Session throws an exception (including any SQLException), you should immediately rollback the database transaction, call Session.close() and discard the Session instance. Certain methods of Session will not leave the session in a consistent state.



do you really think so? what should i do then with already loaded object instances from the first session? throw them away too... through the entire application?... You must be joking...


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 02, 2005 8:36 am 
Newbie

Joined: Wed Aug 31, 2005 4:32 pm
Posts: 13
Thanks for the citation. Just found it in the docs. I cannot believe it is so by design...


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 02, 2005 8:45 am 
Newbie

Joined: Sat Jul 23, 2005 8:31 am
Posts: 18
just forgot to write that i got it from the docs. i myself use hibernate only for webapplications and therefore i never had a problem with closing and reopening sessions if an error ocured.
i can't say whats the best solution. create a single session just for inserting this single object is probably not the best aproach.
i would propose you to use the database to generate the counting number for the fname, so you don't ned to use exceptionhandling.
but if you relay on rollback after exceptions without closing the session it's probably necessary to refactor some stuff, maybe you find in the docs or wiki some hints.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 02, 2005 9:33 am 
Newbie

Joined: Wed Aug 31, 2005 4:32 pm
Posts: 13
chrigi wrote:
just forgot to write that i got it from the docs. i myself use hibernate only for webapplications and therefore i never had a problem with closing and reopening sessions if an error ocured.
i can't say whats the best solution. create a single session just for inserting this single object is probably not the best aproach.
i would propose you to use the database to generate the counting number for the fname, so you don't ned to use exceptionhandling.
but if you relay on rollback after exceptions without closing the session it's probably necessary to refactor some stuff, maybe you find in the docs or wiki some hints.


thanks for your suggestion but i'll probably switch to usual JDBC-based DAO/DTO pattern which i used for years. the architcture of the app is ok for an easy switch.

actually this is the first non-trivial project where i tried to use an 'automated' approach but after some time i realized that it has very serious limitations and is unsuitable for my needs (the same is true for jdo).


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 02, 2005 9:59 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Ahem.

There is actually no difference between Hibernate and JDBC in this matter.

Everything you can safely do with JDBC in terms of recovery from failed transactions, you can also do with Hibernate.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 02, 2005 10:31 am 
Newbie

Joined: Wed Aug 31, 2005 4:32 pm
Posts: 13
gavin wrote:
Ahem.

There is actually no difference between Hibernate and JDBC in this matter.

Everything you can safely do with JDBC in terms of recovery from failed transactions, you can also do with Hibernate.


The main problem for me is the way hibernate manges instances and handles sessions. Imagine (my) situation:

1. I load an instance A via hibernate into memory and store it in a number of collections where it could be possibly modified

2. Now I get the constraint-related exception and (according to the documenation) have to close/reopen session. this has nothing to do with A - just another object.

3. Now I try to get A from new hibernate session and it creates a new java object for me. This is a small problem.

4. Now I try to save my old A (which is still stored in an old collection in my app's memory) and get error with message like 'another object with the same id already exists in the session' or the message about concurrency problems. This is a bigger problem. Of course it can be solved (via some kind of mapping or factory or etc) but in general this approach gives me more problems then I have with plain approach and this is not the only problem - another one is with polymophical classes (see (2) ), another one is with serialization (see (3) ) and who knows what will be next.... ;)

I would agree that for some cases hibernate is excellent but not for mine.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 02, 2005 10:36 am 
Newbie

Joined: Wed Aug 31, 2005 4:32 pm
Posts: 13
What I think is strange is that instance pool/cache is not preserved between sessions. Is it too complex or my case is so rare?


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 02, 2005 2:14 pm 
Expert
Expert

Joined: Sat Jun 12, 2004 4:49 pm
Posts: 915
I try make test for different combinations saving and rollback.It work fine

Vladimir's problem can be :
1) don't close session after rollback or
2) ID generator - I use assigned

Test (complete added)
Table and mapping is simple : table have ID and name

Code:
package yu.co.snpe.test;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

import yu.co.snpe.dbtable.model.hibernate.FinVn;

public class VladimirTest extends BaseTest {

   public VladimirTest(String name) {
      super(name);
   }

   public void testRollback() {

      // delete objects with id 888 and 999 if exist
      Session session = getSessionFactory().openSession();
      Transaction transaction = null;
      try {
         transaction = session.beginTransaction();
         FinVn delObj = (FinVn) session.get(FinVn.class, "888");
         if (delObj != null)
            session.delete(delObj);
         delObj = (FinVn) session.get(FinVn.class, "999");
         if (delObj != null)
            session.delete(delObj);
         transaction.commit();
      } catch (HibernateException e1) {
         transaction.rollback();
      } finally {
         session.close();
      }

      // check for id 11 and it have to exists
      session = getSessionFactory().openSession();
      FinVn obj11 = (FinVn) session.load(FinVn.class,"11");
      assertTrue(obj11 != null);
      session.close();
      FinVn obj1 = new FinVn();
      obj1.setId("11"); // this exists - first time transaction rollback
      FinVn obj2 = new FinVn();
      obj2.setId("999"); // not exists
      session = getSessionFactory().openSession();
      transaction = null;
      try {
         transaction = session.beginTransaction();
         session.save(obj1);
         session.save(obj2);
         transaction.commit();
         fail("commit"); // obj1 exists
      } catch (HibernateException e) {
         transaction.rollback();
      } finally {
         session.close();
      }
      obj2 = new FinVn();
      obj2.setId("888"); // not exists
      session = getSessionFactory().openSession();
      try {
         transaction = session.beginTransaction();
         session.save(obj2);
         transaction.commit();
      } catch (HibernateException e) {
         transaction.rollback();
         fail("rollback"); // ???
      } finally {
         session.close();
      }
      obj2 = new FinVn();
      obj2.setId("888"); // now exists and we will rollback
      obj1 = new FinVn();
      obj1.setId("999");
      session = getSessionFactory().openSession();
      try {
         transaction = session.beginTransaction();
         session.save(obj2);
         transaction.commit();
         fail("commit 2"); // 888 exists
      } catch (HibernateException e) {
         transaction.rollback();
      }
      finally {
         session.close();
      }
      session = getSessionFactory().openSession();
      try {
         transaction = session.beginTransaction();
         session.save(obj1);
         transaction.commit();
      } catch (HibernateException e) {
         transaction.rollback();
         fail("rollback 2");
      }
      finally {
         session.close();
      }
      // 888 and 999 are in database
      session = getSessionFactory().openSession();
      obj1=(FinVn) session.load(FinVn.class,"888");
      assertTrue(obj1!=null);
      obj1=(FinVn) session.load(FinVn.class,"999");
      assertTrue(obj1!=null);
   }
}


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 02, 2005 5:02 pm 
Newbie

Joined: Wed Aug 31, 2005 4:32 pm
Posts: 13
yes, you're right - the problem there is that i don't close the session after an exception thrown. i just couldn't imagine that i have to close session as it leads to some (in my case - painful) consequences (see y explanations above).

thanks you for your time, and thanks to everyone who participated to the discussion.

best


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 17 posts ]  Go to page 1, 2  Next

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.