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.