2013-07-09 110 views
20

多くの同時ユーザーがデータベースにアクセスできるようにする必要があります。各コミット後にセッションを終了しますが、時には自分のコードが次のエラーに陥ることもありますが、何度か同じ操作を行うとエラーを超えて動作します。ネストされたトランザクションはサポートされていないエラーを回避するにはどうすればよいですか?

私の休止状態は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> 
+0

私には競合する危険性があります。独自の 'ThreadLocal'スコープのトランザクションを書くには、多くの落とし穴があります。自分のセッション管理コードを書くことを強くお勧めします。['CurrentSessionContext'](http://docs.jboss.org/hibernate/orm/3.6/javadocs/org/hibernate/context/CurrentSessionContext.html)のいずれかを使用して、実装が提供されます。 –

+0

あなたはどんな例を知っていますか? –

+0

[documentation](http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/architecture.html#architecture-current-session)から始めることもできます。 –

答えて

25

で次のプロパティを追加します。 :例外の場合

  1. 、あなたがカルスがある
  2. セッションを閉じるには、no finallyブロックはありませんngはsession.close()ですが、これはHibernateUtils.closeSession()とは異なります。そのため、ThreadLocalはクリアされません。
  3. 例外のブロックはcatchではありません。その結果、rollbackはありません。
  4. 例外を元に戻すのですか、それとも無視されていますか?

begin()後、「実行する」ブロックで例外がある場合、トランザクションが開いたままで、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()にいくつかの「記帳」のコードを追加することができます。

ので正しい例外処理のためのスニペットをチェック。最終的には、同じスレッドによって1つまたは複数の「取得」された後に「閉じる」が必要です。

私はあなたのスレッドがその作業ユニットをやっている限り、 "get"を1つだけ持ち、セッションを渡すことも考えています。この方法では、おそらく問題を見つけるのが簡単です。


同様の問題を報告するように別の質問があります:Hibernate 4.1.9 (latest final build) reporting `nested transactions not supported

commit()の後にコードを追加して、取引が実際に完了したかどうかを確認することができます(wasCommitted())。

wasCommitted()のJavadocのからの引用:この方法でもコミットの成功した呼び出し()の後にはfalseを返すことができ

。例として、JTAベースの戦略は、トランザクションを開始しなかった場合にcommit()コールにno-opを呼び出します。その場合、wasCommitted()もfalseと報告します。

+1

ありがとうございました。 –

+0

お返事ありがとうございました。私の現在の設定は、多数のユーザーを処理するのに十分だと思いますか? –

+0

@Mir Mooridoあなたの主な問題は解決しましたか?あなたはまだ答えを選択していません。とにかく、あなたの設定が多数のユーザーに適しているかどうかは分かりません。異なる数の同時ユーザーでテストを設定する必要があります。 – Beryllium

5

利用session.beginTransaction()の代わりに、session.getTransaction()。あなたのコード内で)(始めます。新しい作業単位を開始する必要があるので、beginTransactionは新しいトランザクションを開始します。 だからあなたのコードは次のようになります。)のbeginTransaction(詳細な情報を取得するにはHereをクリックして

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

。方法。

私はあなたの問題を解決すると思います。問題が解決しない場合は教えてください。

+1

ありがとうございました。 –

13

おそらくトランザクションを開始し、前のトランザクションをコミットまたはロールバックせずに別のトランザクションを開始しようとしています。プログラムによるトランザクション境界を使用してイディオムは、次のいずれかです。

​​

はいくつかの問題があるかもしれない、あなたの「マイコード」スニペットでは、あなたはhibernate.cfg.xml

<prop key="hibernate.current_session_context_class">thread</prop> 
+0

ありがとうございますupit –

+0

スレッドローカルの必要はありますか? – MayurB

+0

私は私が必要と思った、あなたはその賛否両論を知っていますか? –

関連する問題