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

我的休眠状态是4.2.1。

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

配置
<?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>

最佳答案

在您的“我的代码”代码段中,可能存在一些问题:

  • 如果发生异常,则没有finally块可以关闭 session
  • 您正在调用session.close(),但这不同于HibernateUtils.closeSession()。因此未清除ThreadLocal
  • 没有用于异常(exception)的catch块;结果,没有rollback
  • 您是否抛出异常或被(静默地)忽略?

  • 如果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”,并且只要您的线程正在执行其工作单元,就传递该 session :这样一来,发现问题可能会更容易。

    关于SO的另一个问题报告了类似的问题:Hibernate 4.1.9 (latest final build) reporting `nested transactions not supported

    您可以在commit()之后添加一些代码以检查交易是否确实完成(通过调用wasCommitted())。

    Javadoc中的wasCommitted()引文:

    关于hibernate - 如何避免嵌套事务不支持的错误?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17542157/

    10-09 07:42