Hibernate 如何避免嵌套事务不支持的错误?

Hibernate 如何避免嵌套事务不支持的错误?,hibernate,jakarta-ee,transactions,Hibernate,Jakarta Ee,Transactions,我需要确保许多并发用户能够访问数据库。虽然每次提交后我都会关闭会话,但有时我的代码会遇到以下错误,但当我执行相同的操作几次时,它就会超越错误并正常工作 我的hibernate是4.2.1.Final Messages: nested transactions not supported File: org/hibernate/engine/transaction/spi/AbstractTransactionImpl.java Line number: 152 我的代码 ses

我需要确保许多并发用户能够访问数据库。虽然每次提交后我都会关闭会话,但有时我的代码会遇到以下错误,但当我执行相同的操作几次时,它就会超越错误并正常工作

我的hibernate是4.2.1.Final

Messages:   
nested transactions not supported
File:   org/hibernate/engine/transaction/spi/AbstractTransactionImpl.java
Line number:    152
我的代码

session = HibernateUtil.getSession();
session.getTransaction().begin();       OR session.beginTransaction();
       ...   to do ....
session.getTransaction().commit();
session.close();                        OR HibernateUtil.closeSession();
HibernateUtil

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

public class HibernateUtil {

   private static ServiceRegistry serviceRegistry;
   private static final ThreadLocal<Session> threadLocal = new ThreadLocal();
   private static SessionFactory sessionFactory;
    private static SessionFactory configureSessionFactory() {
        try {

            Configuration configuration = new Configuration();
            configuration.configure();
            serviceRegistry = new ServiceRegistryBuilder()
                                 .applySettings(configuration.getProperties())
                                 .buildServiceRegistry();
            sessionFactory = configuration.buildSessionFactory(serviceRegistry);

            return sessionFactory;
        } catch (HibernateException e) {
            System.out.append("** Exception in SessionFactory **");
            e.printStackTrace();
        }
       return sessionFactory;
  }


  static {
    try {
      sessionFactory = configureSessionFactory();
    } catch (Exception e) {
      System.err.println("%%%% Error Creating SessionFactory %%%%");
      e.printStackTrace();
    }
  }

  private HibernateUtil() {
  }

  public static SessionFactory getSessionFactory() {
    return sessionFactory;
  }

  public static Session getSession() throws HibernateException {
    Session session = threadLocal.get();

    if (session == null || !session.isOpen()) {
      if (sessionFactory == null) {
        rebuildSessionFactory();
      }
      session = (sessionFactory != null) ? sessionFactory.openSession() : null;
      threadLocal.set(session);
    }

    return session;
  }

  public static void rebuildSessionFactory() {
    try {
      sessionFactory = configureSessionFactory();
    } catch (Exception e) {
      System.err.println("%%%% Error Creating SessionFactory %%%%");
      e.printStackTrace();
    }
  }

  public static void closeSession() throws HibernateException {
    Session session = (Session) threadLocal.get();
    threadLocal.set(null);

    if (session != null) {
      session.close();
    }
  }
}
import org.hibernate.hibernateeexception;
导入org.hibernate.Session;
导入org.hibernate.SessionFactory;
导入org.hibernate.cfg.Configuration;
导入org.hibernate.service.ServiceRegistry;
导入org.hibernate.service.ServiceRegistryBuilder;
公共类HibernateUtil{
私有静态ServiceRegistry ServiceRegistry;
私有静态final ThreadLocal ThreadLocal=新ThreadLocal();
私有静态SessionFactory SessionFactory;
专用静态SessionFactory配置SessionFactory(){
试一试{
配置=新配置();
configure.configure();
serviceRegistry=newServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.buildServiceRegistry();
sessionFactory=configuration.buildSessionFactory(serviceRegistry);
返回工厂;
}捕获(休眠异常e){
System.out.append(“**SessionFactory中的异常**”);
e、 printStackTrace();
}
返回工厂;
}
静止的{
试一试{
sessionFactory=configureSessionFactory();
}捕获(例外e){
System.err.println(“%%创建SessionFactory时出错%%”);
e、 printStackTrace();
}
}
私有的HibernateUtil(){
}
公共静态SessionFactory getSessionFactory(){
返回工厂;
}
公共静态会话getSession()引发HibernateeException{
会话=threadLocal.get();
if(session==null | |!session.isOpen()){
if(sessionFactory==null){
重建会话工厂();
}
session=(sessionFactory!=null)?sessionFactory.openSession():null;
threadLocal.set(会话);
}
返回会议;
}
公共静态无效重建会话工厂(){
试一试{
sessionFactory=configureSessionFactory();
}捕获(例外e){
System.err.println(“%%创建SessionFactory时出错%%”);
e、 printStackTrace();
}
}
public static void closeSession()引发HibernateeException{
Session Session=(Session)threadLocal.get();
threadLocal.set(null);
if(会话!=null){
session.close();
}
}
}
配置

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <!-- Database connection settings -->
        <property name="connection.driver_class">
            com.mysql.jdbc.Driver
        </property>
        <property name="connection.url">
            jdbc:mysql://localhost:3306/MyProject
        </property>
        <property name="connection.username">root</property>
        <property name="connection.password"></property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">12</property>

        <!-- SQL dialect -->
        <property name="dialect">
            org.hibernate.dialect.MySQLDialect
        </property>

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>

        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class">
            org.hibernate.cache.NoCacheProvider
        </property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

                <mapping class="com.project.common.Project" />
                <mapping class="com.project.common.School" />
                <mapping class="com.project.common.Address" />
                <mapping class="com.project.common.Female" />
                <mapping class="com.project.common.Male" />
                <mapping class="com.project.common.Credential" />
                <mapping class="com.project.common.Users" />

    </session-factory>

</hibernate-configuration>

com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/MyProject
根
12
org.hibernate.dialogue.mysqldialogue
线
org.hibernate.cache.NoCacheProvider
真的

在代码中使用session.beginTransaction()而不是session.getTransaction().begin()。您需要开始一个新的工作单元,因此beginTransaction将开始一个新事务。 因此,您的代码将如下所示:

session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
       ...   to do ....
transaction.commit();
单击以获取有关beginTransaction()的更多信息;方法


我想这会解决你的问题。如果问题仍然存在,请告诉我。

您可能已经开始了一个事务,并且在没有提交或回滚前一个事务的情况下尝试开始另一个事务。使用编程事务划分时的习惯用法如下:

Transaction transaction = null;
    try {
      session = HibernateUtil.getSession();
      transaction  = session.beginTransaction();
       ...   to do ....
      transaction.commit();
    }
    catch (RuntimeException e) {
        transaction.rollback();
        throw e;
    }
在Hibernate.cfg.xml中添加以下属性

 <prop key="hibernate.current_session_context_class">thread</prop>
线程
在您的“我的代码”片段中,可能存在一些问题:

  • 如果出现异常,则没有
    finally
    块来关闭会话
  • 您正在调用
    session.close()
    ,但这不同于
    HibernateUtils.closeSession()
    。因此,
    ThreadLocal
    未被清除
  • 没有异常的
    catch
    块;因此,没有
    回滚
  • 您是重新引用异常还是(无声地)忽略它们
  • 如果在
    begin()
    之后的“to do”块中出现异常,则事务将保持打开状态,并且
    ThreadLocal
    不会被清除

    您的代码可能正常工作,但在高负载下可能会有(SQL锁)超时等,在这种情况下,偶尔会抛出异常

    因此,请检查每个代码段是否有正确的异常处理:

    final Session session = HibernateUtil.getSession();
    try {
      final Transaction transaction = session.beginTransaction();
      try {
        // The real work is here
        transaction.commit();
      } catch (Exception ex) {
        // Log the exception here
        transaction.rollback();
        throw ex;
      }
    } finally {
      HibernatilUtil.closeSession();
    }
    

    您可以将一些“簿记”代码添加到
    HibernateUtil.getSession()
    HibernateUtil.closeSession()
    :记录每次访问,包括线程的名称。最终,同一线程的一个或多个“get”后面必须跟一个“close”

    在你的情况下,我甚至会考虑只有一个“GET”,并且只要你的线程正在执行它的工作单元,就可以通过这个会话:这样就很容易找到问题。


    还有另一个关于SO的问题,该问题报告了类似的问题:

    您可以在
    commit()
    之后添加一些代码来检查事务是否已真正完成(通过调用
    wasCommitted()

    wasCommitted()
    的Javadoc中的一段引用:

    即使在成功调用commit()之后,此方法也可能返回false。例如,基于JTA的策略如果没有启动事务,就不会执行commit()调用;在这种情况下,他们还将wascommited()报告为false


    我也面临同样的问题,我通过放置tr.commit()解决了我的问题;在每一笔交易后都会运行。 只有在启动任何事务而不关闭前一个事务时,才会发生这种情况

    session = HibernateUtil.getSession();
    
    session.getTransaction().begin();       OR session.beginTransaction();
    
    ...   to do ....
    
    session.getTransaction().commit();
    
    session.close();   OR HibernateUtil.closeSession();