3

Spring 3.1.3.RELEASE で動作する hibernate-release-4.1.8.Final を取得しようとしています。

Spring appContext は次のとおりです。

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="configLocation">
        <value>
            classpath:hibernate.cfg.xml
        </value>
    </property>
    <property name="hibernateProperties">
        <value>
            hibernate.show_sql=true
            hibernate.format_sql=true
            hibernate.current_session_context_class=thread
        </value>
    </property>
    <property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
    <property name="targetDataSource">
        <ref local="mainDataSource"/>
    </property>
</bean>
<!-- mysql with bonecp thread pooling using a lazy jdbc connection -->
<bean id="mainDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
    <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    <property name="jdbcUrl" value="jdbc:mysql:..."
    ...
</bean>

<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
    <property name="dataSource" ref="dataSource"/>
</bean>

<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="*" rollback-for="ServletException" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>
<aop:config>
    <aop:pointcut id="serviceMethods" expression="execution(* com.mytest.service.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods"/>
</aop:config>

上記は、Hibernate 4 統合を示す最新の Spring ドキュメントとかなり似ています。@Transaction注意してください、私はアノテーションよりもスプリング-AOPクロスカットを使用することを好みます. Spring のドキュメントによるとhibernate4.HibernateTransactionManager、宣言型構成の両方のスタイル (注釈と XML) をサポートする必要があります。しかし、それは本当ですか?何が起こるかは次のとおりです。

一般的な DAO 構造:

public abstract class MyHibernateDAOImpl<T> implements BaseDAO<T> {
    // spring-injected sessionFactory
    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public Session getSession() {
        //ignore orm.hibernate4.SessionFactoryUtils for now -- will be explained later
        //Session s = SessionFactoryUtils.openSession(sessionFactory);

        //spring-recommended approach to getting session
        Session s = sessionFactory.getCurrentSession();
        return s;
    }

    //basic query
    public List<UserState> getSomeData() {
        Query query = getSession().createQuery("from SomeData");
        return query.list();
    }
}

注釈は使用されません。私の理解ではHibernateTransactionManagerorm.hibernate4aop で作成されたトランザクションに参加し、ThreadLocalそれをセッションにバインドします。バインドが発生しないように見えますか? それとも、私が扱っているSessionと思うものを扱っていないのでしょうか?

私のアプリは、表示されているものと同じリリース バンドルから提供される spring-web ライブラリを含む標準の Spring-mvc アプリであると仮定します。さらに、ビューはorg.springframework.orm.hibernate4.support.OpenSessionInViewInterceptorセッションの寿命を延ばすために利用しますが、問題はありません...

Tomcat6 で実行すると、次の DEBUG が生成されます...

[2012-11-10 03:08:59,864] INFO [http-8443-exec-3] MyController.logRequest(273) | Session GET /data/InitialData
[2012-11-10 03:08:59,887] DEBUG [http-8443-exec-3] HibernateTransactionManager.doGetTransaction(290) | Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
[2012-11-10 03:08:59,889] DEBUG [http-8443-exec-3] AbstractPlatformTransactionManager.getTransaction(365) | Creating new transaction with name [com.betterment.service.user.impl.UserStateServiceImpl.getAllStates]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-ServletException
[2012-11-10 03:08:59,889] DEBUG [http-8443-exec-3] HibernateTransactionManager.doBegin(352) | Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
[2012-11-10 03:08:59,915] DEBUG [http-8443-exec-3] AbstractTransactionImpl.begin(158) | begin
[2012-11-10 03:08:59,915] DEBUG [http-8443-exec-3] LogicalConnectionImpl.obtainConnection(295) | Obtaining JDBC connection
[2012-11-10 03:08:59,916] DEBUG [http-8443-exec-3] LogicalConnectionImpl.obtainConnection(301) | Obtained JDBC connection
[2012-11-10 03:08:59,916] DEBUG [http-8443-exec-3] JdbcTransaction.doBegin(69) | initial autocommit status: true
[2012-11-10 03:08:59,916] DEBUG [http-8443-exec-3] JdbcTransaction.doBegin(71) | disabling autocommit
[2012-11-10 03:08:59,921] DEBUG [http-8443-exec-3] HibernateTransactionManager.doBegin(413) | Exposing Hibernate transaction as JDBC transaction [org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler@76566fb[valid=true]]

これまでのところは順調です...トランザクションが作成され、接続が確立され、スレッドにバインドされたセッションが見つかったという言い回しさえあります。DAO.getSomeDataログ出力は、メソッド内にデバッグ カーソルを配置します。メソッドgetSession()が呼び出される直前、およびクエリを作成して list() をプルする直前です。

現在、getSession()が呼び出されると aSessionが返されますが、デバッガーで検査することはできません - 奇妙です。から hql クエリを作成しようとするとSessionTransactionロールバックします。これは、実際には にバインドされていないことを意味しThreadLocalます。

[2012-11-10 03:16:06,972] DEBUG [http-8443-exec-3] AbstractPlatformTransactionManager.processRollback(843) | Initiating transaction rollback
[2012-11-10 03:16:06,973] DEBUG [http-8443-exec-3] HibernateTransactionManager.doRollback(496) | Rolling back Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
[2012-11-10 03:16:06,973] DEBUG [http-8443-exec-3] AbstractTransactionImpl.rollback(203) | rolling back
[2012-11-10 03:16:06,974] DEBUG [http-8443-exec-3] JdbcTransaction.doRollback(164) | rolled JDBC Connection
[2012-11-10 03:16:06,974] DEBUG [http-8443-exec-3] JdbcTransaction.releaseManagedConnection(126) | re-enabling autocommit
[2012-11-10 03:16:06,982] DEBUG [http-8443-exec-3] HibernateTransactionManager.doCleanupAfterCompletion(564) | Not closing pre-bound Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] after transaction
[2012-11-10 03:16:06,983] DEBUG [http-8443-exec-3] SessionImpl.disconnect(564) | Disconnecting session
[2012-11-10 03:16:06,983] DEBUG [http-8443-exec-3] LogicalConnectionImpl.releaseConnection(314) | Releasing JDBC connection
[2012-11-10 03:16:06,983] DEBUG [http-8443-exec-3] LogicalConnectionImpl.releaseConnection(332) | Released JDBC connection
[2012-11-10 03:16:06,983] DEBUG [http-8443-exec-3] ConnectionProxyHandler.physicalConnectionReleased(219) | HHH000163: Logical connection releasing its physical connection
[2012-11-10 03:16:06,984] DEBUG [http-8443-exec-3] ConnectionProxyHandler.physicalConnectionReleased(219) | HHH000163: Logical connection releasing its physical connection
[2012-11-10 03:16:06,984] DEBUG [http-8443-exec-3] ConnectionProxyHandler.physicalConnectionReleased(219) | HHH000163: Logical connection releasing its physical connection
[2012-11-10 03:16:06,997] DEBUG [http-8443-exec-3] OpenSessionInViewInterceptor.afterCompletion(141) | Closing Hibernate Session in OpenSessionInViewInterceptor
[2012-11-10 03:16:06,999] ERROR [http-8443-exec-3] ErrorFilter.doFilter(50) | Unexpected error in session 'mySession' javax.servlet.ServletException: org.hibernate.HibernateException: createQuery is not valid without active transaction

私が試した次のバリアントは、に戻ることでしたSessionFactoryUtils。効果はありますが、副作用が大きいようです。これは減少orm.hibernate4.SessionFactoryUtilsしたものであり、hibernate3 のものではないことに注意してください。これは とSessionFactoryのみを公開openSessioncloseSessionます。このファクトリでは、getSession()次のようになります。

public Session getSession() {
    //try with orm.hibernate4.SessionFactoryUtils
    Session s = SessionFactoryUtils.openSession(sessionFactory);
    return s;
}

SessionFactoryUtils実行すると、QueryTranslator最終的にデータの結果が得られるようになります。問題は、外部トランザクション全体が完了するまで閉じないセッションを開いたことです。を呼び出すたびgetSession()に新しい接続が作成され、すぐにスレッドが不足します。これは、JDBC 接続の取得後に BoneCP と Tomcat がフリーズするのを許可する最大接続を示す MySQL>show processlist によって観察されます。

[2012-11-10 03:31:56,887] DEBUG [http-8443-exec-3] LogicalConnectionImpl.obtainConnection(295) | Obtaining JDBC connection
[2012-11-10 03:31:56,887] DEBUG [http-8443-exec-3] LogicalConnectionImpl.obtainConnection(301) | Obtained JDBC connection

Tomcat は永遠にこのまま座ります。

回避策は積極的な接続管理のようです。hibernate.connection.release_mode=after_statement私の<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">定義を紹介しました。

after_statement のみが機能しているようです。この設定を使用すると、プログラムは、些細な実行および重要な実行に対して問題なしで実行されます。hibernate.current_session_context_class=thread影響はないようですのでご注意ください。全体的に release_mode の使用は非常にハックに感じます。各ステートメントの後に接続を積極的に解放する必要があると、負荷がかかっているアプリに望ましくない結果が生じるはずです。

それで - 何が起こっているのですか?getCurrentSession()アクティブなトランザクションがスレッドにバインドされていないセッションを返さないのはなぜですか? トランザクションをいつ開始するかを判断する唯一の方法は@Transactionalアノテーションですか? hibernate4.LocalSessionFactoryBeanSpring Docs はトピックが非常に少ないようです。

さらに、下に切り替えるhibernate3.LocalSessionFactoryBean(および hibernate4 を参照する他の構成を hibernate3 に戻す) と、厄介なjava.lang.NoClassDefFoundError:が生成org/hibernate/cache/CacheProviderされます。これは、stackoverflow の他のスレッドによってカバーされます。

何か案は?いくつかの入力に本当に感謝します。ありがとうございました!

4

0 に答える 0