Java 休眠:同时有两个或多个事务:事务已处于活动状态

Java 休眠:同时有两个或多个事务:事务已处于活动状态,java,hibernate,rest,jersey,Java,Hibernate,Rest,Jersey,我有一个REST API,当我几乎同时发布POST和GET时,我会遇到以下异常: 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.T

我有一个REST API,当我几乎同时发布POST和GET时,我会遇到以下异常:

 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)
它们位于不同的类上,因此不包含全局属性

发生故障的线路如下:

HibernateSession hs = new HibernateSession();
hs.createTransaction(); // Crash
Wich指的是我的班级休眠会话:

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();
        }

    }

}
异常实际上在session.beginTransaction()行中

我总是做一个hs.commitclose(),在catch()块和404s中我总是做一个rollbackclose()

问题是,当我发布这样的消息时:

HibernateSession hs = new HibernateSession();
hs.createTransaction();
hs.session.save(whatever);
hs.commitclose();
返回200,这是正常的,但是GET可能会崩溃,出现上述异常。 当我创建一个新的HibernateSession实例时,为什么Hibernate似乎试图共享该事务

只有当我在很短的时间内进行两次查询时(我猜是在另一个查询的开始和提交之间启动事务),才会发生这种情况。所以我猜Hibernate认为会话属性是静态的或者类似的东西

提前感谢您的帮助! 编辑:根据请求,
HibernateUtil.java
(问题一定不在这里,但可能有助于理解):


尝试将代码重新编写为

public class HibernateSession {

    public Session session;
    int id;
    Transaction t = null;

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

    public void commitclose() {
        t.commit();
        session.close();
    }

    public void rollbackclose() {

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

    }

}

对于
t

的每个引用,都需要进行非正常的空检查。根据
createTransaction
逻辑,您正在从
SessionFactory
获取当前会话,并从中启动一个事务

问题就在这里

假设您已经创建了
HibernateSession
对象并启动了事务,但它仍在进行中。所以您还没有结束交易

现在您创建了另一个
HibernateSession
并尝试启动事务,这样做将引发异常

你的密码是什么

public void createTransaction() {
    session = HibernateUtil.getSessionFactory().getCurrentSession();
    session.beginTransaction();
}
一定是这样

public void createTransaction() {
    session = HibernateUtil.getSessionFactory().openSession();
    session.beginTransaction();
}
getSessionFactory().openSession()总是打开一个新的会话,在完成操作后必须关闭该会话


getSessionFactory().getCurrentSession()返回绑定到上下文的会话-您不需要关闭它。

实际上,您的实际代码中有许多缺点:

  • 每次调用代码时,您都在创建
    HibernateSession
    类的一个新实例,因此您将有许多实例试图访问同一会话
  • 调用
    hs.createTransaction()时,
    HibernateSession
    的每个实例都将尝试创建一个新事务,这就是为什么在这一行出现异常,因为已经有打开的事务,并且您正在尝试打开一个新的事务,因为您正在调用
    session.beginTransaction()transaction.close()
您可以在这里做的是使您的
HibernateSession
类成为单例,因此只有一个实例可用,您可以查看该实例以了解如何实现它的更多详细信息


createTransaction
方法中,wich应该更好地命名为
getTransaction
,而不是只调用
session.beginTransaction()
如果当前事务存在,您需要获取它。您可以使用
session.getTransaction()
方法检查它,并确保将代码包装在
try…catch
块中,您可以检查它以了解更多详细信息。

您有一些与设计相关的缺陷:

  • 您不应该使用
    getCurrentSession()
  • 正如jboss中所述,您应该使用以下习惯用法:

     Session sess = factory.openSession();
     Transaction tx;
     try {
         tx = sess.beginTransaction();
         //do some work
         ...
         tx.commit();
     }
     catch (Exception e) {
         if (tx!=null) tx.rollback();
         throw e;
     }
     finally {
         sess.close();
     }
    
  • 你应该遵循积垢模式
  • 对于每个操作(创建、读取、更新、删除),在类中创建一个方法。每种方法都应创建自己的会话和事务,因为如下所述:

    会话不是线程安全对象-无法由多个线程共享 线程。您应该始终使用“每个请求一个会话”或“一个会话” “每个事务的会话数”

    您的方法在某种程度上是有效的,但也可以查看在中创建的DAO对象

    解决方案:

    代码失败的原因很简单,因为事务仍在进行中,这与您以前与数据库的交互有关。这就是为什么要执行
    finally{session.close()}
    ——以确保在退出该方法时会话已关闭。我假设在某个时刻,您的
    commit()
    没有成功,并在此后未关闭的事务/会话中离开了休眠状态

    要解决这个问题,您应该在代码中插入一个session.close(),执行它,然后实现我建议的try-catch-finally块,以确保它在将来关闭。

    我刚刚更改了它

    session = HibernateUtil.getSessionFactory().getCurrentSession();
    


    我正在访问已打开的工厂会话。

    是否可以添加HibernateUtil…@Ashish451当然我已经添加了解决方案。。您可以尝试执行相同的异常,但不执行session.beginTransaction();它在t=session.beginTransaction()上;最后一次尝试。替换
    t=session.beginTransaction()带有
    t=session.getTransaction()但我需要开始。它应该是非活动的,因为我第一次获取。我可以检查是否处于活动状态,但这只是一个解决方法,我真正需要的是每次类实例化时,事务都成为一个非常新的实例。@CarlosLópez这就是为什么您应该使用会话工厂!您只有一个Hibernate会话的实例,而其中一个被卡在事务中,因为您没有正确关闭它。@nwenz3l是的,问题出在getCurrentTransaction()上,而不是我想做的openTransaction上。正如您在编辑中看到的,他有一个单例工厂,可以用来实例化新会话,那太好了。他的实际错误是,在提交给b的方法中没有
    finally{session.close()}
    或者甚至没有
    try{..}
    session = HibernateUtil.getSessionFactory().getCurrentSession();
    
    session = HibernateUtil.getSessionFactory().openSession();