-->
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.  [ 15 posts ] 
Author Message
 Post subject: What do exceptions do to the EntityManager exactly?
PostPosted: Thu Mar 29, 2007 12:30 pm 
Newbie

Joined: Fri Jun 23, 2006 12:52 pm
Posts: 11
Okay, I've read the Hibernate EntityManager and Hibernate Core docs and both state very clearly that after any exception the EntityManager/Session should be closed immediately because it is not usable. I'm trying to figure out exactly what state the EntityManager is in after a PersistenceException is thrown from either an EntityTransaction or the EntityManager directly (via a flush() call).

Here are two examples I came up with that test out the state of the EntityManager. The first one does a query after the exception and tests out lazy fetching as well. The second one performs an insert after the exception. Both of these work fine and either perform the queries or perform the inserts. So, I'm left wondering, why do I need to close the EntityManager. It seems perfectly fine to me.

The setup is there are two tables, User and Email and User has a unique constraint on name and User as a collection of Emails.

Code:
    public void testLazyFetching() throws SQLException {
        executeViaJDBC("insert into User values (1, 'Fred')");
        executeViaJDBC("insert into Email values (1, 1, 'fred@example.com')");
        executeViaJDBC("insert into Email values (2, 1, 'fred@somecompany.com')");

        executeViaJDBC("insert into User values (2, 'Ted')");
        executeViaJDBC("insert into Email values (3, 2, 'ted@example.com')");

        EntityManager em = emf.createEntityManager();

        // Blow up the EntityManager
        EntityTransaction et = em.getTransaction();
        try {
            et.begin();
            User newFred = new User();
            newFred.setName("Fred");
            em.persist(newFred);
            em.flush();
            et.commit();
        } catch (Exception e) {
            // Ignore for this example
            et.rollback();
        }

        // Fetch an existing user and test lazy fetching
        User fred = (User) em.createQuery("select user from User user where user.name='Fred'").getSingleResult();
        try {
            fred.getEmails().size();
            fred.getEmails().get(0).getEmail();
            fred.getEmails().get(1).getEmail();
            Assert.fail("Session was still usable for query and lazy fetching");
        } catch (PersistenceException pe) {
            // This is expected because the session should be corrupt
        }

        em.close();
    }


Here's number 2

Code:
    public void testEntityManagerCorruptionInsert() throws SQLException {
        executeViaJDBC("insert into User values (1, 'Fred')");
        executeViaJDBC("insert into Email values (1, 1, 'fred@example.com')");
        executeViaJDBC("insert into Email values (2, 1, 'fred@somecompany.com')");

        executeViaJDBC("insert into User values (2, 'Ted')");
        executeViaJDBC("insert into Email values (3, 2, 'ted@example.com')");

        EntityManager em = emf.createEntityManager();

        // Blow up the EntityManager
        EntityTransaction et = em.getTransaction();
        try {
            et.begin();
            User newFred = new User();
            newFred.setName("Fred");
            em.persist(newFred);
            em.flush();
            et.commit();
        } catch (Exception e) {
            // Ignore for this example
            et.rollback();
        }

        // Add a new user to corrupt session
        et = em.getTransaction();
        et.begin();
        User john = new User();
        john.setName("John");
        em.persist(john);
        em.flush();
        et.commit();

        // Ensure the new user isn't there since the EntityManager is corrupt
        Connection c = ds.getConnection();
        Statement s = c.createStatement();
        ResultSet rs = s.executeQuery("select * from User where name = 'John'");
        Assert.assertFalse(rs.next());

        em.close();
    }


So, what's the full story on this stuff? Can I continue to use the EntityManager after exceptions because it sure looks like I can? Or am I missing something that will bite me later down the road?


Top
 Profile  
 
 Post subject: JPA specification results
PostPosted: Fri Apr 06, 2007 3:57 pm 
Newbie

Joined: Fri Jun 23, 2006 12:52 pm
Posts: 11
Well, I read through the JPA specification for something that would clear this up and it turns out that JPA doesn't work the same way Hibernate does. In fact, it only refers to transactions and rolling things back. If an exception occurs at any point, the current transaction is set into rollback state, but the entity manager is not corrupted.

This goes against the EntityManager documentation provided by Hibernate on handling exceptions. The Hibernate docs state:

If the EntityManager throws an exception (including any SQLException), you should immediately rollback the database transaction, call EntityManager.close() (if createEntityManager() has been called) and discard the EntityManager instance. Certain methods of EntityManager will not leave the persistence context in a consistent state. No exception thrown by an entity manager can be treated as recoverable. Ensure that the EntityManager will be closed by calling close() in a finally block. Note that a container managed entity manager will do that for you. You just have to let the RuntimeException propagate up to the container.

JPA goes directly against that it seems and what Hibernate states should in fact not be the case, unless I'm missing something. From the JPA perspective the EntityManager is intact, but the transaction has failed.

Anyone have more information on this topic? I think is extremely vital to figuring out how to approach standard situations with relational databases, especially unique key constraints.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 12, 2007 5:17 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
I can't remember where, but the spec state the same constraint. I think it says, all exception are unrecoverable but 2 of them.

_________________
Emmanuel


Top
 Profile  
 
 Post subject: Talk to Max
PostPosted: Thu Apr 12, 2007 5:47 pm 
Newbie

Joined: Fri Jun 23, 2006 12:52 pm
Posts: 11
emmanuel wrote:
I can't remember where, but the spec state the same constraint. I think it says, all exception are unrecoverable but 2 of them.


I talked to Max and he looked in the specification. It turns out that only the transaction needs to be rolled back from what he could find. Of course the specification only refers to queries mostly, but there is a section that talks to EntityManager and exceptions:

Quote:
Runtime exceptions thrown by the methods of the EntityManager interface will cause the current transaction to be rolled back.


So, it looks to be correct be spec that the EntityManager and the session are fine after an exception. However, it looks as though Hibernate doesn't always ensure this. So, it might be that the specification needs to be modified or that Hibernate needs to be modified. Otherwise, something is out of sync with the other.

From my research, the EntityManager seems to behave okay after exceptions have occurred and the offending transaction has been rolled back. I would assume that unless major cascading has failed or some other type of error the EntityManager is fine.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 12, 2007 6:02 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Seriously, the intend of the spec was to prevent any subsequent use of the em when an exception (those that mark the tx for rollback) happens.
As a matter of fact, it is illegal to use a transactional resource once the transaction has been marked for rollback (JTA through JTS inspired by OTS forbid that).

feel free to ask a clarification the Specification Lead.

_________________
Emmanuel


Top
 Profile  
 
 Post subject: JTA? Not sure what you mean.
PostPosted: Sun Apr 15, 2007 11:26 pm 
Newbie

Joined: Fri Jun 23, 2006 12:52 pm
Posts: 11
emmanuel wrote:
Seriously, the intend of the spec was to prevent any subsequent use of the em when an exception (those that mark the tx for rollback) happens.
As a matter of fact, it is illegal to use a transactional resource once the transaction has been marked for rollback (JTA through JTS inspired by OTS forbid that).


True, but this is not what I'm saying. I'm stating that I will first call rollback and then reuse the EntityManager. This works fine in my example code above and seems to be working fine in most of my cases. I'm not stating that the specification doesn't imply that once the transaction is SET for rollback it is still able to be used, I'm stating that after it has been ROLLED BACK it is able to be used.

This is a HUGE difference. In fact, my usage is how most transactional resources behave. Once you roll them back, they are ready to go for the next transaction. This is how JDBC connections work and most databases work. Hibernate is not like this. If forces you to throw out the resource after you roll it back and then re-create it. I can't think of another transactional resource you have to completely thrown away after you roll it back.

emmanuel wrote:
feel free to ask a clarification the Specification Lead.


I will.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 16, 2007 5:46 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
Just to be clear; this is what the spec states:

Section 3.7 Summary of Exceptions

"All instances of PersistenceException except for instances of NoRe-
sultException and NonUniqueResultException will cause the currenttransaction, if one is active, to be marked for rollback"

So after those two exceptions you can/should be able to use the EntityManager. Notice that these occurs in very well defined places (search the spec for them, it's for methods on Query).

For everyone else its marking the tx for rollback; effictivly rendering the underlying connection useless (for not to talk about any inconsistent state that could be in the session/entitymanager because of the exception)

Thus; no you should not use a em after an exception have occurred and for the usecase you have described it's very easy to reverse the logic so no exception would ever need to be thrown.

And yes I agree the spec is not very strict on wether an em can be used or not. BUT it says the current transaction says it will be *marked* for rollback - not actually rolled back hence until commit occurs the em is by deduction basically useless since everything you will do will be discarded.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject: Sorry, this is not what it says.
PostPosted: Mon Apr 16, 2007 12:59 pm 
Newbie

Joined: Fri Jun 23, 2006 12:52 pm
Posts: 11
max wrote:
Just to be clear; this is what the spec states:

Section 3.7 Summary of Exceptions

"All instances of PersistenceException except for instances of NoRe-
sultException and NonUniqueResultException will cause the currenttransaction, if one is active, to be marked for rollback"


I feel as though you guys are missing what the specification is saying.

Let's go over this thing in detail.

"All instances of PersistenceException except for NoResultException and NonUniqueResultException" - This means every OTHER exception, including any exception caused by an underlying SQLException, in particular a unique key violation exception such as EntityExistsException.

"will cause the current transaction, if one is active" - This means that all the OTHER exceptions are the cause. Specifically, NoResultException and NonUniqueResultException will not impact the current transaction at all.

"to be marked for rollback" - This means that the current TRANSACTION will be marked for rollback. This would be the exact same as my calling the method

Code:
transaction.setRollbackOnly()


There is absolutely no difference in me calling this method and what the specification is stating about how PersistenceExceptions should be handled, according to the specification.

Quote:
So after those two exceptions you can/should be able to use the EntityManager. Notice that these occurs in very well defined places (search the spec for them, it's for methods on Query).


Exactly.

Quote:
For everyone else its marking the tx for rollback; effictivly rendering the underlying connection useless (for not to talk about any inconsistent state that could be in the session/entitymanager because of the exception)


Where is the specification does is state this? It doesn't state anywhere that the EntityManager should be marked as invalid or should be discarded or anything like that at all. This is a Hibernate specific constraint. Furthermore, it never states that the underlying JDBC connection is invalid because it isn't - ever. JDBC connections do not become invalid after exceptions and in most cases you can continue to work within a JDBC transaction after exceptions. Try it, it works just fine. Here's my simple example of how MySQL transactions continue to work fine after exceptions:

Code:
mysql> select * from User;
+----+------+
| id | name |
+----+------+
|  1 | Fred |
| 12 | John |
|  2 | Ted  |
+----+------+
3 rows in set (0.00 sec)

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into User values (3, "Fred");
ERROR 1062 (23000): Duplicate entry 'Fred' for key 2
mysql> insert into User values (4, "Bob");
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from User;
+----+------+
| id | name |
+----+------+
|  4 | Bob  |
|  1 | Fred |
| 12 | John |
|  2 | Ted  |
+----+------+
4 rows in set (0.00 sec)


As you can easily tell, the exception occurred but I was still able to persist more data in the same JDBC transaction.

Quote:
Thus; no you should not use a em after an exception have occurred and for the usecase you have described it's very easy to reverse the logic so no exception would ever need to be thrown.


You seem to have made a fairly large assumption based on prior Hibernate handling of the Session. The specification does not constrain the EntityManager in this way. In terms of the use case I provided, there is no way to guarantee that reversing the logic (doing a select prior to a insert) will work. In fact this is usually to be avoided in a transactional situation because it is the only way you can guarantee at some point that the application WILL fail. At some point you will be in a race condition where your select tells you the key doesn't exist and then your insert will tell you otherwise. You can test this in MySQL with two connections. MySQL will block and wait on inserts until it can 100% be certain that the insert will succeed or fail. Therefore, you can easily make a case where this race condition exists and fails.

Quote:
And yes I agree the spec is not very strict on wether an em can be used or not. BUT it says the current transaction says it will be *marked* for rollback - not actually rolled back hence until commit occurs the em is by deduction basically useless since everything you will do will be discarded.


I think that by default implementors should assume the same semantics as the underlying JDBC connection. If exceptions occur you should execute a rollback, but then be able to use the JDBC connection some more. I think Hibernate is kinda suck in the mentality that the Session HAS to be thrown out after exceptions and I personally feel that this is the wrong approach.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 16, 2007 1:07 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
Using objects/data from a tx/connection that is marked to be rolledback might be *possible* to do; it does not mean it is the *correct* thing to do.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject: I disagree
PostPosted: Mon Apr 16, 2007 1:21 pm 
Newbie

Joined: Fri Jun 23, 2006 12:52 pm
Posts: 11
max wrote:
Using objects/data from a tx/connection that is marked to be rolledback might be *possible* to do; it does not mean it is the *correct* thing to do.


In the example I have above, it is perfectly fine. In fact I feel that most data level errors are completely handlable. It is the system level errors that are scary. So, I my thinking it would make sense to have two buckets, one for data exceptions and one for system exceptions. The specification could then put more bounds around the EM based on the buckets.

For system exceptions the EM would be completely invalid and implementations would be required to mark the EM as unusable.

For data exceptions the EM would still be intact and the ET would be invalid and marked for rollbackOnly. I would further like to have the specification address the fact that the EM is still completely usable, but it would be at the discretion of the application to determine if the Objects in the first level cache are valid. This would be easier if the EM did not use implicit updates or EM scoped caching (according to one of my pitfalls), because it would allow the EM to mark a closed object graph as invalid when the application makes calls to an update method.


Top
 Profile  
 
 Post subject: Re: I disagree
PostPosted: Mon Apr 16, 2007 2:43 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
voidmain wrote:
max wrote:
Using objects/data from a tx/connection that is marked to be rolledback might be *possible* to do; it does not mean it is the *correct* thing to do.


In the example I have above, it is perfectly fine. In fact I feel that most data level errors are completely handlable. It is the system level errors that are scary. So, I my thinking it would make sense to have two buckets, one for data exceptions and one for system exceptions. The specification could then put more bounds around the EM based on the buckets.

For system exceptions the EM would be completely invalid and implementations would be required to mark the EM as unusable.

For data exceptions the EM would still be intact and the ET would be invalid and marked for rollbackOnly. I would further like to have the specification address the fact that the EM is still completely usable, but it would be at the discretion of the application to determine if the Objects in the first level cache are valid. This would be easier if the EM did not use implicit updates or EM scoped caching (according to one of my pitfalls), because it would allow the EM to mark a closed object graph as invalid when the application makes calls to an update method.


We were open for discussion regarding a refinement of which exception were recoverable and which were not. The EG hadn't had time though. Push the point to the spec lead so that it's not forgotten for the next revision.

PS: Some containers might accept that you continue playing with the connection after the tx has been marked for rollback but it's a loose behavior w/r/t the transaction spec.

_________________
Emmanuel


Top
 Profile  
 
 Post subject: Re: JTA? Not sure what you mean.
PostPosted: Mon Apr 16, 2007 2:45 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
voidmain wrote:
This is how JDBC connections work and most databases work. Hibernate is not like this. If forces you to throw out the resource after you roll it back and then re-create it. I can't think of another transactional resource you have to completely thrown away after you roll it back.


contrary to DB connections, Persistence context are not heavy, so usually not pooled nor constrained.

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 18, 2007 7:28 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
Quote:
I would further like to have the specification address the fact that the EM is still completely usable, but it would be at the discretion of the application to determine if the Objects in the first level cache are valid.


So if you think your app can do this why don't you just take that control and create a new EM and reattach the object graph you think is valid ?

And as I explained to you earlier, by reverseing your logic you never would end up in the situation of getting the exception in the first place - resolving your problem completly for this *simple* case.

Quote:
This would be easier if the EM did not use implicit updates or EM scoped caching (according to one of my pitfalls), because it would allow the EM to mark a closed object graph as invalid when the application makes calls to an update method.


Again, these "pitfalls" is what makes it so easy to use compared to doing every operation explicitly which when used often hides much bigger issues which a state based ORM can track/detect for you.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject: Issue with EntityExistsException
PostPosted: Tue May 01, 2007 9:11 pm 
Newbie

Joined: Tue May 01, 2007 12:25 pm
Posts: 5
As per our application design, we have been Hibernate EntityManager 3.2.1 in Weblogic Server 10.0.

We do have an EmployeeMaster table where the unique constraint is applied on the Employee 'FIRSTNAME' field of this table. The Employee ID field has been designated as the primary key over here.

While trying to persist a duplicate employee entity (with the same 'FIRSTNAME' that is already as part of the table), the hibernate entity manager seems to throw only the 'org.hibernate.exception.ConstraintViolationException' whereas we were looking for an EntityExistsException as per the documentation.

I have also attached my code snippet below for your reference:

public <T extends PersistenceObject> T create(T pObject) throws LMSException {
try {
this.getEntityManager().persist(pObject);
}
catch (EntityExistsException aEntityExistsException) {
System.out.println("Duplicate Entity Exception:"+aEntityExistsException);
}

return pObject;
}

Can you kindly help me out on how to sort out this issue?

Regards,
Sathish


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 02, 2007 3:45 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
EntityExists is only for when the same entity already exists (e.g. it has the same id as an existing one)

ConstraintViolation is for any other constraint violation (like duplicates in unique columns)

_________________
Max
Don't forget to rate


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