Hibernate org.hibernate.TransactionException: nested transactions not supported on jaxrs - java

I am using jersey with mysql and hibernate 4 and c3p0. I have created a initialization servlet that configures hibernate and sets the current session context class to thread.
I have created hibernateUtils class that contains static methods for getting and committing sessions and I am using a filter to start a session on inbound request and commit it upon response.
The problem is that at some random intervals I am getting org.hibernate.TransactionException: nested transactions not supported exception, but I am not trying to create a new session except on the filter.
Correct me if I am wrong but when setting the current session class to thread I don't need to create a threadlocal in the hibernateutil, hibernate does this. So my question is, is this a safe way to handle that and what could cause the error happening on random intervals?
====================== EDIT ===========================
Sorry for not posting the code earlier.
So the filter implements the ContainerRequestFilter,ContainerResponseFilter
in the request filter I am doing
Session session = sessionfactory.getCurrentSession();
session.getTransaction().begin();
session.setDefaultReadOnly(readOnly);
and in the response
Transaction transaction = sessionfactory.getCurrentSession().getTransaction();
try {
if (transaction != null && !transaction.wasCommitted()
&& !transaction.wasRolledBack() && transaction.isActive()) {
transaction.commit();
}
} catch (HibernateException e) {
Transaction transaction = sessionfactory.getCurrentSession().getTransaction();
try {
if (transaction != null && transaction.isActive()) {
transaction.rollback();
}
} catch (HibernateException e) {
} finally {
Session session = sessionfactory.getCurrentSession();
try {
if (session != null && session.isOpen()) {
session.close();
}
} catch (HibernateException e) {
log.error("Closing session after rollback error: ", e);
throw e;
}
}

It seems that you are using programmatic transaction demarcation in your filter (as far as I understood). So please double check that you terminate properly each transaction, nevermind what append during the request (i.e. rollback if you get an exception and commit otherwise) :
try {
session.getTransaction().begin();
// call the filter chain
session.getTransaction().commit()
}
catch (RuntimeException e) {
session.getTransaction().rollback();
}
Without the code it's difficult to be sure, but I guess that for some request you didn't terminate the transaction properly (i.e. by a commit or by a rollback). So the transaction remains associated to the thread and the thread go back to the thread pool (in a very strange state since there is still a transaction associated with it), then another request reuse the same thread, a new transaction is created in the filter... and you got the exception.
EDIT
After looking carrefully at your code, it (may) confirms my assumptions.
Look at the flow when transaction.wasRolledBack()==true : it won't be commited nor rolled back.
And if you the javadoc for Transaction.wasRolledBack() :
Was this transaction rolled back or set to rollback only?
If the transaction is marked as "RollBack only" : it will return true, but it don't means that the transaction is ended. It means that the only possible ending state for the transaction is "RollBack".
But, on the other hand the same javadoc also say this:
Returns: boolean True if the transaction was rolled back via this local transaction; false otherwise.
I found that ambiguous.
So I suggest you to do this:
if (transaction != null && !transaction.wasCommitted()
&& !transaction.wasRolledBack() && transaction.isActive()) {
transaction.commit();
}else if(transaction.wasRolledBack()){
transaction.rollback();
}

Related

Using Spring #Transactional in a method with multiple operations

I have a service which runs every few seconds and processes some records from a queue which is stored in the database. I noticed that a #Transactional attribute added and was trying to figure out what it's usage is and wanted to make sure it's the right usage.
#Scheduled(initialDelay = 10000, fixedDelay = 10000)
#Transactional
public void notificationTask() {
Integer txId = myDao.getMinTxIdByStatusCode("Pending");
myDao.updateStatusByTxId(txId, "Processing");
boolean status = true;
Transaction tx = myDao.getTxById(txId);
if (txId != null) {
status = myService.processTx(txId, myTx.getX(), myTx.getY());
if (status) {
myDao.updateStatusByTxId(txId, "Complete");
} else {
myDao.updateStatusByTxId(txId, "Failed");
}
}
}
My main question here is, if for some reason either the getTxById or the processTx methods fail, does that mean with the #Transational attribute, it will roll back the updateStatusByTxId? What is a use case where the Transactional attribute would be used here?
When you use #Transactional on a method, Spring wraps the entire method in a transaction. This means that a new transaction is started before the method is entered and committed after the method is exited.
If there is an exception, the whole transaction will be rolled back. That's what is called "atomicity": transactions are "all or nothing".
Thus, #Transactional is a "shortcut" for something like this when using Hibernate:
#Scheduled(initialDelay = 10000, fixedDelay = 10000)
public void notificationTask() {
Transaction transaction = null;
try {
Session session = sessionFactory.openSession(); //Hibernte session
transaction = session.beginTransaction();
//... your stuff
Integer txId = myDao.getMinTxIdByStatusCode("Pending");
myDao.updateStatusByTxId(txId, "Processing");
boolean status = true;
Transaction tx = myDao.getTxById(txId);
if (txId != null) {
status = myService.processTx(txId, myTx.getX(), myTx.getY());
if (status) {
myDao.updateStatusByTxId(txId, "Complete");
} else {
myDao.updateStatusByTxId(txId, "Failed");
}
}
//... your stuff done
transaction.commit();
}catch (Exception ex) {
ex.printStackTrace();
transaction.rollback();
}
}
So, if your method updateStatusByTxId is just a database call (is not flushing, nor committing or has is own nested transaction): yes, it is rolled back.
And since the transaction is also active, when entering processTx, this service call will also be in the same transaction, even if you add an additional #Transactional to processTx. Except you explicitly start a new transaction by e.g. #Transactional(Transactional.TxType.REQUIRES_NEW).
Additionally, Spring has a really detailed doc:
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#transaction

Why JPA/Hibernate transaction is active even when I did not start one explicitly

My problem is that JPA/Hibernate returns true for a call of entityManager.getTransaction().isActive() even when I did not explicitly start a transaction (see code below).
The problem here is that I want to read something from the database and a SerializationException is ok in this scenario, because this just indicates that the persisted object does not fit to the actual code any more and needs to be recalculated. Instead of just returning null the code below throws the following exception:
Transaction rollback failed.
org.hibernate.TransactionException: Unable to rollback against JDBC Connection
This shows me, there must have been a transaction somewhere which I did not start in my code. The finally block in the code above is
final EntityManager entityManager = Persistence.createEntityManagerFactory("test").createEntityManager();
try {
final TypedQuery<Test> query = entityManager.createQuery("SELECT t FROM test t", Test.class);
return query.getResultList();
} catch (final PersistenceException e) {
if (e.getCause() instanceof SerializationException) {
LOG.debug("Implementation changed meanwhile. That's ok - we return null.");
return null;
}
throw e;
} finally {
EntityManagerCloser.closeEntityManager(entityManager);
}
And the EntityManagerCloser looks like this:
public final class EntityManagerCloser {
private static final Logger LOG = LoggerFactory.getLogger(EntityManagerCloser.class);
public static void closeEntityManager(EntityManager entityManager) {
if (entityManager.getTransaction().isActive()) {
try {
entityManager.getTransaction().rollback();
} catch (PersistenceException | IllegalStateException e) {
LOG.error("Transaction rollback failed.", e);
}
}
if (entityManager.isOpen()) {
try {
entityManager.close();
} catch (IllegalStateException e) {
LOG.error("Closing entity manager failed.", e);
}
}
}
}
Hibernate docs says "Always use clear transaction boundaries, even for read-only operations". So do I really need to insert a
entityManager.getTransaction().begin();
....
<do read here>
....
entityManager.getTransaction().commit();
around every read operation I perform on the database?
I could implement another closeEntityManager method for read-only operations without the rollback transaction block but I want to understand why there IS a transaction at all. Thanks for any help!
The problem is that when you call entityManager.getTransaction(); a new transaction object will be created. So it is better to save the transaction reference to a variable as shown below.
Transaction txn = entityManager.getTransaction();
if (txn.isActive()) {
try {
txn.rollback();
} catch (PersistenceException | IllegalStateException e) {
LOG.error("Transaction rollback failed.", e);
}
}
Thanks to Jobin I quickly found the solution to my problem:
I think I need to call entityManager.isJoinedToTransaction() in my closeEntityManager method before calling entityManager.getTransaction().isActive().
This will prevent the EntityManagerCloser to start its own transaction which I can not rollback later because I did not explicitly call transaction.begin() on it.

Make c3p0 behave like Hibernate built-in connection pool

Probably this is stupid or weird question but I'm facing a strange bug in the app for many weeks and do not know how to solve it.
There are some Quartz jobs that periodically updating database (change the status of orders and stuff). There is only Hibernate 3.1.3 without spring and all transactions handled in code manually with explicit call session.close() in finally block.
It all worked fine with Hibernate built-in connection pool, however after I have changed built-in connection pool to c3p0 pool there are some bugs appeared connected with database transaction/session management. There is no exceptions or anything in the log files, so it is hard to tell what exactly was the reason.
Is there any way to make c3p0 connection pool behave like built-in pool by configuration? I need only one c3p0 feature - checking dead connections. Before this pool was implemented there was idle SQL Connection Reset issue. To keep connections alive I decided to use c3p0 pooling instead of built-in.
here is my current c3p0 configuration:
c3p0.min_size=0
c3p0.max_size=100
c3p0.max_statements=0
c3p0.idle_test_period=600
c3p0.testConnectionOnCheckout=true
c3p0.preferredTestQuery=select 1 from dual
c3p0.autoCommitOnClose=true
c3p0.checkoutTimeout=120000
c3p0.acquireIncrement=2
c3p0.privilegeSpawnedThreads=true
c3p0.numHelperThreads=8
Thanks in advance.
c3p0 is an old version: 0.9.0.4, because I have Java 1.4 environment.
Here is a rough example how transactions are managed by the code:
SessionFactory sessionFactory = null;
Context ctx = null;
Object obj = null;
ctx = new InitialContext();
obj = ctx.lookup("HibernateSessionFactory");
sessionFactory = (SessionFactory) obj;
session = sessionFactory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
// some transactional code
if (!tx.wasRolledBack() && !tx.wasCommitted()) {
tx.commit();
}
} catch (Exception ex) {
if (tx != null && !tx.wasRolledBack() && !tx.wasCommitted()) {
// if it is runtime exception then rollback
if (ex instanceof RuntimeException) {
logger.log(Level.ERROR, "10001", ex);
try {
tx.rollback();
} catch (RuntimeException rtex) {
logger.log(Level.ERROR, "10002", rtex);
}
}
else {
// attempt to commit if there are any other exceptions
try {
tx.commit();
} catch (RuntimeException rtex) {
logger.log(Level.ERROR, "10004", rtex);
// if commit fails then try to rollback
try {
tx.rollback();
} catch (RuntimeException rtex2) {
logger.log(Level.ERROR, "10002", rtex2);
}
// then rethrow this exception
throw rtex;
}
}
}
finally {
session.close();
}

JPA EntityManager doesn't get closed while GCing (Performance issue)

We have been using annotation based JPA with Hibernate as JpaVendorAdapter.
We had to schedule a job to refresh an entire table data using spring scheduler.
The code is as follows,
#Scheduled(fixedDelay=120000)
public void refreshTable() {
EntityManager em = null;
try {
EntityManagerFactory emf = entityManager.getEntityManagerFactory();
em = emf.createEntityManager();
em.getTransaction().begin();
/// do something like delete and fill table
// this block is done for the sake of batch mode operation
em.getTransaction().commit();
} catch (Exception e) {
logger.error("Failed to refresh table", e);
} finally{
if(em != null && em.getTransaction().isActive()){
em.getTransaction().rollback();
logger.info("Failure while refreshing table, rolling back transaction.");
}
}
}
This used to build memory utilization and caused application hang.
We added, at the end of finally block,
if(em != null){
em.close();
}
Which solved the memory problem.
So, why does not EntityManager execute close() while being GC'ed?
The JPAConnector has various connections associated with it and it does not close all of them whereas waiting for garbage collector to do it is not a wise approach.
Closing the connections(i.e EntityManager and EntityManagerFactory) as and when they are no more needed is the best way to address this issue.
Hope this helps!
Good luck!

Hibernate: Do you need to manually close with sessionFactory?

I have way too many threads being used. I keep running out of memory in my unit tests. Do I need to close my session if I'm using sessionFactory. Won't the commit below end the session?
Session session = sessionFactory.getCurrentSession();
Transaction transaction = null;
try
{
transaction = session.beginTransaction();
transaction.commit();
}
catch (Exception e)
{
if (transaction != null)
{
transaction.rollback();
throw e;
}
}
finally
{
//Is this close necessary?
session.close();
}
No, it won't end the session. One session can span any number of transactions. Close the session explicitly. BTW such things are clearly documented.
In yout catch, verify if the transaction isActive() too.

Categories