2012-11-20 6 views
0

이 문제로 인해 귀찮게 괴롭 히고 잠시 동안 귀찮았습니다. 바라기를 다른 누군가는 무슨 일이 일어나고 있는지 조금은 단서가 있습니다.Bizarre Spring 트랜잭션 Hibernate 엔티티를 사용하는 JUnit 테스트가 null입니다.

저는 Spring 트랜잭션 JUnit 테스트가 @Rollback(true)입니다. 테스트는 HibernateTransaction에 랩핑되어 단위 테스트가 끝날 때 데이터베이스 변경 사항을 자동으로 롤백합니다. 이것은 작동하는 것으로 보입니다.하지만이 단 하나의 쿼리를 사용하는이 기괴한 시나리오에서는 단 하나의 유닛 테스트에서만 @Transactional 비즈니스 로직 메서드가 null을 반환합니다.

@Test 
@Rollback(true) 
public void testObscureIssue() throws Exception { 
    // Not important... 
    l = createLeague(); 
    t1 = createTeam(l); 
    User u = userBo.getUser(1L, false); 

    Player player = TestUtils.getInstance().createTestData(Player.class, 1).get(0); 
    player.setUser(u); 
    player.setGender("M"); 
    player.setStartingActivityLevel(ActivityLevelEnum.Sedentary); 
    playerBo.addOrUpdate(player); 
    TeamPlayer tp = new TeamPlayer(t1, player); 
    leagueStructureBo.addOrUpdate(tp); 

    // This test will pass 10% of the time, seemingly random. Randomness only inside of unit test 
    Team t = playerBo.getCurrentTeam(player.getPlayerID()); 
    if (t == null) throw new OutOfMemoryError("What is this... I don't even..."); 

    Team expected = playerBo.getCurrentTeam(player.getPlayerID()); 
    assertNotNull(expected); 
    assertEquals(t1, expected); 
} 

그래서 방법 playerBo.getCurrentTeam는 항상 응용 프로그램에서 제대로 반환하고 난 후 한 번에 코드 한 줄을 단계별 단위 테스트에 어디 중단 점을 배치하면 항상 제대로 반환합니다. 그러나 디버깅없이 단순히 단위 테스트를 실행할 때 대부분의 경우 실패합니다.

여기서는 일부 레이싱 조건이 발생한다고 생각하지만이 Transactional 메서드를 호출하기 전에 Thread.sleep(400000L); 문을 넣더라도 여전히 실패합니다. 트랜잭션 방법

코드 :

@Override 
@Transactional 
public Team getCurrentTeam(long playerId) { 
    String qry = "select t from Team as t inner join t.teamPlayers as tp " + 
      "inner join tp.player as tpp where tpp.playerID = :playerId and (((current_timestamp() between tp.startDate and tp.endDate " + 
      "and tp.endDate is not null) or (tp.endDate is null and current_timestamp() > tp.startDate)))"; 
    Object wtf = sessionFactory.getCurrentSession().createQuery(qry) 
      .setParameter("playerId", new Long(playerId)).uniqueResult(); 
    return (Team)wtf; 
} 

트랜잭션 속성은 봄 Hibernate4 TransactionManager에 대한 모든 기본이다.

코드 예제에서이 팀 엔티티를 명확하게 만들었고 로그에 생성 된 새 레코드의 ID가 표시됩니다. 나는이 ID로 HQL을 사용하여 레코드를 직접 질의 할 수 있으며 반환 할 것이지만,이 Transactional 메소드의 위의이 HQL 쿼리는 디버그 모드에서 단계별로 실행하지 않으면 여전히 null을 반환합니다.

가장 바깥 쪽 트랜잭션이 롤백 될 때까지 아무 것도 롤백되지 않는다는 느낌을 받기 때문에 중첩 트랜잭션에 문제가 있습니까? 왜이 특정한 방법에 대해서만? Hibernate 4 나 Spring 3.1.1의 버그입니까? MySQL InnoDB를 사용하고 있는데, MySQL InnoDB가 데이터베이스 트랜잭션을 처리하는 방식에 문제가 될 수 있습니까?

내가 아이디어가 완전히 없기 때문에 시도해 볼만한 추가 제안 사항은 환영합니다.

답변

1

내 생각 엔이 문제는 current_timestamp()의 사용으로 인한 것입니다. 이제 TeamPlayer를 시작 날짜로 사용하고 중단 점을 넣으면 현재 시간 소인이 체계적으로 시작 날짜보다 더 거,습니다. 반면 중단 점을 두지 않으면 코드가 충분히 빠르며 코드의 10 %가 시간, 팀 플레이어의 시작 날짜와 동일한 현재 시간 소인을 갖습니다.

+0

지금은 분명해 보이지만 정확히 문제였습니다. 도와 줘서 고마워! –

관련 문제