2011-08-23 22 views
1

私たちは今これを数週間にわたってオンオフしています。2回目のDBアクションはトランザクションで実行をフリーズします

最初のコード、

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" 
    xsi:schemaLocation=" 
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd"> 

    <context:annotation-config /> 
    <context:component-scan base-package="com.nmsc" /> 
    <tx:annotation-driven proxy-target-class="true"/> 

    <bean id="sessionFactory" 
     class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
     <property name="configLocation"> 
      <value>hibernate.cfg.xml</value> 
     </property> 
     <property name="configurationClass"> 
      <value>org.hibernate.cfg.AnnotationConfiguration</value> 
     </property> 
    </bean> 

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
     <property name="sessionFactory" ref="sessionFactory"/> 
    </bean> 

</beans> 

私のDAOクラス

@SuppressWarnings("unused") 
@Repository("com.nmsc.hibernateDAO.SSOUserDAO") 
@Transaction 
public class SSOUserDAO implements SSOUserDAOSPI{ 
    private static Logger logger = Logger.getLogger(SSOUserDAO.class); 

    @Autowired(required=true) 
    private SessionFactory sessionFactory; 

    @Transactional 
    public Integer saveUpdate(SSOUser user) { 
     sessionFactory.getCurrentSession().saveOrUpdate(user); 

     return user.getIdUser(); 
    } 

OK]をクリックして、今、私のJUnitに私はこの

@Test 
    @Transaction 
    public void testStoreRetrieve() { 
     SSOUserDAOSPI userDAO = ServiceProviderContext.find(SSOUserDAOSPI.class); 

     System.out.println("test"); 
     userDAO.deleteAllInUserTable(); 
     SSOUser user = buildTestUser(); 

     Integer id = userDAO.saveUpdate(user); 

     user.setIdUser(id); 

     // retrieve the user from the database 
     SSOUser retrievedUser = userDAO.getByID(id); 

     checkResults(user, retrievedUser); 
    } 

削除ユーザーをすればちょうど見つけるに動作しますが、 saveupdateを実行し、実行が停止します。何のエラーも、何もない、あなたがプロセスを殺すまで、ただ凍っている。私は

Integer id = userDAO.saveUpdate(user); 

をすれば

同様に、それは完璧に動作し、ユーザーを挿入し、私は

Integer id = userDAO.saveUpdate(user); 
Integer id2 = userDAO.saveUpdate(user2); 

を行う場合には、最初のユーザーを挿入し、第二に凍結するだろう。私たちがSpringトランザクションを実装しようとする前に、何か似たようなことをしました(システムの他の部分に対して行う必要がありました)。しかし、user2は挿入しませんでしたが、hibernateログファイルは、 。

これが休止状態またはポストグルであるかどうかはわかりません。私たちが春を絵に持ってくる前に似ていたので、春が何をしているのかは疑問です。

EDITのTRY TWO

OK、ここに私のDAOクラス

@SuppressWarnings("unused") 
@Repository 
public class SSOUserDAO implements SSOUserDAOSPI{ 
    private static Logger logger = Logger.getLogger(SSOUserDAO.class); 

    @Autowired(required=true) 
    private SessionFactory sessionFactory; 

    public Integer saveUpdate(SSOUser user) { 
     sessionFactory.getCurrentSession().saveOrUpdate(user); 
     return user.getIdUser(); 
    } 
public void deleteAllInUserTable() { 
     // delete everything in the table to run the test 
     logger.debug("beginning delete"); 
     if (sessionFactory == null){ 
      logger.debug("session factory null"); 
     } else 
      logger.debug("sessionfactory not null"); 

     Query q = sessionFactory.getCurrentSession().createQuery("delete from SSOUser"); 
     q.executeUpdate(); 
    } 

であり、私はイム理解場合は、正しく正確に何をしているこの

@Test 
    @Transactional(propagation=Propagation.REQUIRED) 
    public void testStoreRetrieve() { 

     SSOUserDAOSPI userDAO = ServiceProviderContext.find(SSOUserDAOSPI.class); 

     System.out.println("test"); 
     userDAO.deleteAllInUserTable(); 
     SSOUser user = buildTestUser(); 

     Integer id = userDAO.saveUpdate(user); 

     user.setIdUser(id); 

     // retrieve the user from the database 
     SSOUser retrievedUser = userDAO.getByID(id); 

     checkResults(user, retrievedUser); 
    } 

に私のテストを変更あなたは(そのジャニットがそれを実行しているという事実を除いて)やっているのですが、同じ例外があります。私たちはおそらく将来的にはスプリングテストに切り替える予定ですが、当面は既存のテストを実行する必要があります。

org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here 
    at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63) 
    at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:687) 
    at com.nmsc.hibernateDAO.SSOUserDAO.deleteAllInUserTable(SSOUserDAO.java:121) 
    at com.nmsc.hibernateDAO.SSOUserDAO_Test.testStoreRetrieve(SSOUserDAO_Test.java:55) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) 
    at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 

私にナットを駆動thatsの部分は、私の初期のログは、その春はBeanがトランザクションマネージャで管理されていることを十分に認識している私に語ったこの

Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor' 
1651 [main] DEBUG org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'SSOUserDAO' to bean named 'sessionFactory' 
1651 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor' 
1653 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Finished creating instance of bean 'SSOUserDAO' 

を示しています。だから私は、トランザクションマネージャーはこれを知っている必要がありますが、それはそうではないように見える豆のインスタンスを取得します。

THREE

OK EDITのTRYは、私はこの

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = 
{ 
    "classpath:transaction-service.xml" 
}) 
public class SSOUserDAO_Test extends JunitHelperClass { 
    private static Logger logger = Logger.getLogger(SSOUserDAO_Test.class); 

    @Resource 
    SSOUserDAOSPI userDAO; 

    @Test 
    @Transactional(propagation=Propagation.REQUIRED) 
    public void testStoreRetrieve() { 

     //SSOUserDAOSPI userDAO = ServiceProviderContext.find(SSOUserDAOSPI.class); 

     System.out.println("test"); 
     userDAO.deleteAllInUserTable(); 
     SSOUser user = buildTestUser(); 

     Integer id = userDAO.saveUpdate(user); 

     user.setIdUser(id); 

     // retrieve the user from the database 
     SSOUser retrievedUser = userDAO.getByID(id); 

     checkResults(user, retrievedUser); 
    } 

に私のテストを変更し、それがユーザーを挿入しようとしたとき、私は戻って、同じロックアップにしています。削除はうまく動作し、ユーザーはフロップします。

答えて

1

@Transactionが何であるかわかりませんが、その間に分散している@Transactionalがあります。トランザクションのデッドロックが発生していると、それほど驚くことはありません。特別に設計されていない限り、ユーザーの要求に対応するメソッド呼び出しの特定の連鎖は通常、正確に1つのトランザクション内で発生し、DAOレベルではなくその上のあるレベルで発生する必要があります。トランザクションは、一般に、ユーザーがデータベースからのすべての読み込み、ビジネスロジック、およびそのアクションを実行するために必要なデータベースへの保存のいずれかを要求し、特定のユーザーの何らかのアクションまたはその他の要求が満たされた場合にのみ終了します。トランザクション管理を整理すると、問題が解決される可能性があります。

編集:

  • これはDAOではないことを

    @Transactional 
    public void modifyUser(int userId, User newUser) { 
        validateInput(newUser); 
        User existingUser = userDao.load(userId); 
        copyUpdateableProperties(newUser, existingUser); 
    } 
    

    注:例として、どこかであなたはこのような何かを行くべき方法を持っている必要があります。それはDAOを使用します。

  • ここではDAOではなくトランザクションが確立されています。
  • オブジェクトがトランザクションのスコープ内でロードおよび変更されたときに、トランザクションのコミット時に変更が保存されるため、明示的な「保存」コールはありません。

問題の原因となる可能性はありますが、テスト中のuserDAO.deleteAllInUserTable();という行は、明確なコードの匂いです。まず、このようなものはセットアップ方法に属しています。これはテスト環境を準備するためです。第2に、より洗練されたアプローチは、テストの最後にロールバックされるトランザクション内で各テストを実行することです。これは、Spring test frameworkを使用するときに無料で利用できる機能です。

+0

私はそれを最初に試みました。 DAOからすべてのトランザクションアノテーションを削除したとき 'org.hibernate.HibernateException:スレッドにバインドされていないHibernateセッションはありません。コンフィグレーションでは非トランザクション型のセッションをここで作成できません。 \t at org.springframework.orm.hibernate3 DAOクラスのtranasctional声明で.SpringSessionContext.currentSession(SpringSessionContext.java:63) で org.hibernate.impl.SessionFactoryImpl.getCurrentSessionで\t(SessionFactoryImpl.java:687) \t '私は – scphantm

+0

があるロックアップを取得私は自分のDAOをトランザクションマネージャーに結びつけるか、それともバックグラウンドで起こるのでしょうか? – scphantm

+0

はい、それが私が「ちょうど1つ」と言った理由です。これは、Spring管理のトランザクションが進行中でなく、SessionFactory.getCurrentSession()を呼び出すと起こります。要は、同じトランザクション内で複数のDAO呼び出しを行う可能性が高いため、DAOよりも高いレベルでトランザクションを管理する必要があります。 –