Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate: Two or more transactions at the same time: Transaction already active

I have a REST API and when I make a POST and a GET nearly the same time I get this exception:

 SEVERE: The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
java.lang.IllegalStateException: Transaction already active
    at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:52)
    at org.hibernate.internal.AbstractSharedSessionContract.beginTransaction(AbstractSharedSessionContract.java:409)
    at sun.reflect.GeneratedMethodAccessor89.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:355)
    at com.sun.proxy.$Proxy58.beginTransaction(Unknown Source)
    at utils.HibernateSession.createTransaction(HibernateSession.java:15)
    at api.ConversationsREST.getMessages(ConversationsREST.java:128)

They are on different classes so no global attributes implied.

The line which fails is this one:

HibernateSession hs = new HibernateSession();
hs.createTransaction(); // Crash

Which refers to my class HibernateSession:

public class HibernateSession {

    public Session session;

    public void createTransaction() {

        session = HibernateUtil.getSessionFactory().getCurrentSession(); //THIS WAS WRONG
 //EDIT:session = HibernateUtil.getSessionFactory().openSession(); //THIS IS RIGHT
        session.beginTransaction();
    }

    public void commitclose() {

        session.getTransaction().commit();
        session.close();

    }

    public void rollbackclose() {

        try {
            session.getTransaction().rollback();
            session.close();
        } catch (Exception hibernateexception) {
            hibernateexception.printStackTrace();
        }

    }

}

The exception is actually on the line session.beginTransaction()

I always make a hs.commitclose() and in the catch() blocks and the 404s I always make a rollbackclose();

The problem is that when I make a POST messages like this:

HibernateSession hs = new HibernateSession();
hs.createTransaction();
hs.session.save(whatever);
hs.commitclose();

Returns 200 and it's ok but then the GET may crash with the exception above. As I am making a new instance of HibernateSession, why Hibernate seems to be trying to share that transaction?

This only happens when I make both queries in a very short time (I guess starting a transaction between the beginning and the commit of another one). So I guess Hibernate is thinking that session attribute is static or something like that...

Thank you in advance for your help!

EDIT: As requested, HibernateUtil.java (the problem must not be here but may help to understand):

package utils;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {

    private static SessionFactory sessionFactory;

    public static SessionFactory getSessionFactory() {

        if (sessionFactory == null) {

            sessionFactory = build();

        }
        return sessionFactory;

    }

    private static SessionFactory build() {

        try {

            return new Configuration().configure().buildSessionFactory();

        } catch (Throwable ex) {

            System.err.println("Initial SessionFactory creation failed: " + ex);
            throw new ExceptionInInitializerError(ex);
        }

    }

}
like image 835
Carlos López Marí Avatar asked Jan 27 '23 22:01

Carlos López Marí


1 Answers

As per your createTransaction logic, you are getting current session from SessionFactory and starting a transaction from it.

Here is the problem.

Lets assume you have created HibernateSession object and started transaction but it is still in progress. So you haven't close transaction yet.

Now you created another HibernateSession and try to start transaction, doing this will throw exception.

So your this code

public void createTransaction() {
    session = HibernateUtil.getSessionFactory().getCurrentSession();
    session.beginTransaction();
}

has to be this

public void createTransaction() {
    session = HibernateUtil.getSessionFactory().openSession();
    session.beginTransaction();
}

getSessionFactory().openSession() always opens a new session that you have to close once you are done with the operations.

getSessionFactory().getCurrentSession() returns a session bound to a context - you don't need to close this.

like image 190
MyTwoCents Avatar answered Jan 31 '23 08:01

MyTwoCents