簡體   English   中英

如何避免嵌套事務不支持錯誤?

[英]How to avoid nested transactions not supported error?

我需要確保許多並發用戶能夠訪問數據庫。 雖然在每次提交后我都會關閉會話,但有時我的代碼會遇到以下錯誤,但是當我執行相同的操作幾次時,它會超過錯誤並起作用。

我的休眠是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();
    }
  }
}

組態

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

在“我的代碼”代碼段中,可能存在一些問題:

  1. 在異常的情況下,沒有finally塊來關閉會話
  2. 您正在調用session.close() ,但這與HibernateUtils.closeSession()不同。 因此ThreadLocal不會被清除。
  3. 沒有catch的異常塊; 因此,沒有rollback
  4. 你是否重新拋出異常或是否(無聲地)被忽略?

如果在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()添加一些“簿記”代碼:記錄每次訪問,包括線程的名稱。 最終,同一個線程中的一個或多個“獲取”必須后跟“關閉”。

在你的情況下,我甚至會考慮只有一個“獲取”,並且只要你的線程正在執行其工作單元就通過會話:這樣可能更容易找到問題。


還有一個關於SO的問題報告了類似的問題: Hibernate 4.1.9(最新的最終版本)報告不支持嵌套事務

如果事務已經真正完成(通過調用wasCommitted() ),你可以在commit()之后添加一些代碼來檢查。

來自wasCommitted()的Javadoc的wasCommitted()

即使在成功調用commit()之后,此方法也可能返回false。 例如,如果沒有啟動事務,基於JTA的策略會在commit()上調用no-op; 在這種情況下,他們還將wasCommitted()報告為false。

您可能已經開始了一個事務,並嘗試在沒有提交或回滾前一個事務的情況下開始另一個事務。 使用程序化事務划分時的習慣用法如下:

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>

在代碼中使用session.beginTransaction()而不是session.getTransaction()。begin()。 您需要開始一個新的工作單元,因此beginTransaction將開始一個新的事務。 所以你的代碼看起來像:

session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
       ...   to do ....
transaction.commit();

單擊此處獲取有關beginTransaction()的更多信息; 方法。

我認為這將解決您的問題。 如果問題仍然存在,請告訴我。

我遇到了同樣的問題,我通過放置tr.commit()解決了我的問題; 每筆交易后的功能。 只有在未關閉上一個事務的情況下啟動任何事務時才會發生

session = HibernateUtil.getSession();

session.getTransaction().begin();       OR session.beginTransaction();

...   to do ....

session.getTransaction().commit();

session.close();   OR HibernateUtil.closeSession();

看起來你也犯了同樣的錯誤。

我遇到了類似的問題:org.hibernate.TransactionException:不支持嵌套事務

在我的情況下,我打開了一個會話並嘗試保存。 沒有提交,我調用了另一個方法並調用了session.beginTransaction(); 所以它拋出錯誤。 為了避免這種情況,我將會話對象作為方法參數發送,並且只調用session.save而不是再次開始。 實際使用會話對象。 它對我有用!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM