2011-08-23 2 views
1

우리는 몇 주 동안이 작업을 계속하고 있습니다.두 번째 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(); 
    } 

좋아, 내 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 만 삽입 할 수는 없었지만 사용자는 삽입하지 않았지만 최대 절전 모드 로그 파일은 실제로 두 번째 사용자를 삽입했음을 나타냅니다 .

이것이 최대 절전 모드 나 포스트그레스 모드인지 알 수 없습니다. 우리가 봄을 그림 속으로 가져 오기도 전에 비슷한 일을했기 때문에 봄이 무엇을하고 있는지 의심 스럽다.

편집 TRY 두

좋아, 여기 내 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); 
    } 

에 내 테스트를 변경 당신은 (마이너스 그 junit가 그것을 실행한다는 사실을 제외하고)하지만 나는 같은 예외를 얻는다. 우리는 앞으로 스프링 테스트로 전환 할 것입니다.하지만 당분간은 기존 테스트를 실행해야합니다. 모두 300 개 정도입니다. 나를 미치게

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) 

부품 그게 내 초기화 로그가 봄 알려줍니다 빈은 트랜잭션 관리자에 의해 관리되고 있음을 충분히 인식이

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' 

을 보여주고있다. 그래서 콩의 인스턴스를 얻을 때 트랜잭션 관리자는 이것을 알아야하지만 그렇지 않은 것처럼 보입니다.

확인 편집 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 사이에는 트랜잭션 교착 상태가 발생해도 놀라운 일은 아닙니다. 특별히 설계되지 않은 한, 사용자 요청에 해당하는 특정 메소드 호출 체인은 일반적으로 정확히 하나의 트랜잭션 내에서 발생해야하며 트랜잭션은 DAO 레벨에서 발생하지 않아야합니다. 트랜잭션은 일반적으로 사용자가 데이터베이스, 비즈니스 논리 및 해당 작업을 수행하는 데 필요한 데이터베이스에 저장하는 모든 로딩에서 특정 작업을 요청한 시점부터 특정 작업 또는 특정 작업에 대한 특정 사용자의 요청이 충족 될 때 종료됩니다 . 트랜잭션 관리를 바로 잡으면 문제가 해결 될 것입니다.

편집 : 예를 들어, 어딘가에 당신이 이런 식으로 뭔가를 가야하는 방법이 있어야합니다

  • 이것은 DAO 아니라고

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

    참고. DAO를 사용합니다.

  • 여기서는 DAO가 아니라 트랜잭션이 설정됩니다.
  • 명시 적 "저장"호출이 없습니다. 객체가 트랜잭션 범위 내에서로드되고 수정되면 트랜잭션이 커밋 될 때 수정 사항이 저장됩니다.

잠재적으로 문제의 원인이 될 수 있지만 테스트에서 userDAO.deleteAllInUserTable(); 줄은 고유 코드 냄새가 있습니다. 첫째, 테스트 환경을 준비하면서 설치 방법에 속합니다. 둘째, 훨씬 더 깔끔한 접근법은 테스트가 끝나면 롤백 된 트랜잭션 내에서 각 테스트를 실행하는 것입니다. Spring test framework을 사용할 때 무료로 사용할 수있는 기능입니다.

+0

나는 그것을 먼저 시도했다. DAO에서 모든 트랜잭션 주석을 제거 할 때 org.hibernate.HibernateException : 스레드에 바인드 된 최대 Hibernate 세션이 없으며 여기서는 트랜잭션이 아닌 트랜잭션을 생성 할 수 없습니다. \t at org.springframework.orm.hibernate3 .SpringSessionContext.currentSession (SpringSessionContext.java:63) org.hibernate.impl.SessionFactoryImpl.getCurrentSession에서 \t (SessionFactoryImpl.java:687) 내가 유치장 – scphantm

+0

를 얻을 DAO 클래스에 tranasctional 문 에서 \t가'있다 내 설정에서 DAO를 트랜잭션 관리자와 연결 시키거나 백그라운드에서 수행해야하는 작업이 있습니까? – scphantm

+0

예, 그렇기 때문에 제가 "정확히 하나"라고 말한 것입니다. 이는 진행중인 Spring 관리 트랜잭션이없고 SessionFactory.getCurrentSession()을 호출 할 때 발생합니다. 요점은 거래가 DAO보다 높은 수준에서 관리되어야한다는 것입니다. 동일한 트랜잭션 내에서 여러 DAO 호출을해야 할 가능성이 높습니다. –

관련 문제