2010-04-02 4 views
13

, 그것은 Hibernate에 의해 던져Hibernate 세션을 깨는 방법? Hibernate 참조에서

모든 예외가 치명적인 것을 여러 번 언급된다. 즉, 데이터베이스 트랜잭션을 롤백하고 현재 Session을 닫아야 함을 의미합니다. 예외를 던진 Session으로 작업하는 을 계속할 수 없습니다.

기존 응용 프로그램 중 하나는 단일 세션을 사용하여 파일의 많은 레코드를 DB 테이블로 업데이트/삽입합니다. 각 레코드 갱신/삽입은 별도의 트랜잭션에서 수행되며 커밋되거나 오류가 발생하면 롤백됩니다. 그런 다음 다음 레코드에 대해 새 트랜잭션이 열리는 등의 작업이 수행됩니다. 그러나 처리의 중간에 HibernateException이 잡힌 경우에도 동일한 세션이 전체 프로세스에서 사용됩니다. 우리는 JBoss 4.2에서 Hibernate 3.24.sp1과 함께 Oracle 9i btw를 사용하고 있습니다.

위의 책을 읽으면이 디자인이 실패 할 수 있음을 알았습니다. 그래서 각 레코드 업데이트마다 별도의 세션을 사용하도록 앱을 리팩토링했습니다. 모의 세션 팩토리가있는 단위 테스트에서 각 레코드 업데이트에 대해 새로운 세션을 요청하고 있음을 확인할 수 있습니다. 여태까지는 그런대로 잘됐다.

그러나 전체 응용 프로그램을 테스트하는 동안 세션 실패를 재현 할 수있는 방법이 없습니다 (스트레스 테스트 btw입니까, 아니면 ...?). 우리는 DB의 청취자를 닫는 것을 생각했지만 응용 프로그램이 DB에 대한 연결을 열어 놓고 있다는 것을 깨달았습니다. 청취자는 이러한 연결에 영향을 미치지 않습니다. (이 앱은 매일 밤 스케줄러에 의해 활성화되는 웹 앱이지만 브라우저를 통해 활성화 될 수도 있습니다.) 그런 다음 앱에서 업데이트를 처리하는 동안 DB에서 이러한 연결 중 일부를 죽이려고했습니다. 이로 인해 일부 오류가 발생했습니다 업데이트하지만, 앱은 행복하게 나머지 레코드를 계속 업데이트합니다. 분명히 Hibernate는 전체 세션을 깨지 않고 두절 된 연결을 다시 열 수있을 정도로 영리하다.

Google의 앱이 원래 형태로도 충분히 견고하기 때문에 중요한 문제는 아닙니다. 그러나 문제는 나를 계속 괴롭 히고 있습니다. 어떤 상황에서

  1. 가 최대 절전 모드 세션이 실제로 사용할 수 없게 될 않는 HibernateException가 발생 후 : 내가 알고 싶습니다 (:과 증상은 무엇인가 업데이트)?
  2. 테스트에서이를 재현하는 방법 (업데이트 :, 단위 테스트가 아닌 통합이 바람직 함)?
  3. (예 : 시험에 대한 적절한 용어는 무엇입니까?) HibernateException이가 던진 후 어떤 상황에서

답변

4

가 최대 절전 모드 세션이 실제로 사용할 수 없게 될합니까?

흥미로운 질문입니다. 나는 꽤 예외적으로 세션이 여전히 "작동 중"이었던 경우를 보았다고 확신한다. 문제는 이것이 보장되지 않는다는 것입니다. 이걸 좀 더 파헤쳐 야해.

업데이트 :가 최대 절전 모드 포럼에 최대 절전 모드 개발자에서 this message을 인용 : 예외가 발생했을 때

최대 절전 모드 세션은 버려야한다.데이터베이스와 관련하여 일관성없는 상태로 유지 될 수 있습니다. 읽기 전용 세션에서는 세션 수준 캐싱을 사용하지 않으므로이 경우가 아닙니다. 예외가 발생하면 다른 방법으로는 세션 레벨 캐시를 지울 수 있습니다 (하지만 깨끗한 해결책이 아니다 그것은 미래의 문제와 문제가 발생할 수 있습니다 나는이 방법처럼 개인적으로하지 않습니다).

Session이 "기술적으로 사용 가능"한 경우 실제로 문제가 발생하지 않으므로 문제가 예상대로 작동하지 않을 수 있습니다. 그리고 당신은 분명히 그것을 원치 않습니다.

어떻게 시험이 재현?

당신은 ConstraintViolationException를 얻을 수 무결성 제약 조건을 위반하여 예를 들어, 슬로우 서브 클래스를 일으키는 조건을 위반 의도적으로 할 수있다. 그와 같은 경우는 어떻습니까?

Session session = HibernateUtil.getCurrentSession(); 

try { 
    session.beginTransaction();  
    // execute some code that violates a unique constraint 
    ... 
    session.getTransaction().commit(); 
} catch (HibernateException e) { 
    session.getTransaction().rollback(); 
} 

// keep using the session 
try { 
    session.beginTransaction();  
    ... 
    session.getTransaction().commit(); 
} catch (HibernateException e) { 
    session.getTransaction().rollback(); 
} 
// do we reach this point? 

그러나 이것이 무엇인가를 증명할 지 확신하지 못합니다. 내 말은, 세션이 여전히 작동한다면, 우리는이 특별한 경우에 대해서만 결론을 내릴 수 있다는 것입니다.

업데이트 : 내 제안을 잊어 버리면 아무 것도 증명하지 않습니다. 그리고 실제로, 나는 예상대로 가지 작업 (그리고 여전히 "사고"가 될 수있다)을 HibernateException 후 것을 증명 (기술적 및 기능적으로) 매우 복잡 할 것이라고 생각합니다. 그래서 아무것도 증명하려고 시도하는 대신, 권장 사항 (또는 제안 된 대안을 따르는 것이 맞지만 모든 트랜잭션에 대해 Sessionclose 새 예외를 요청할 것입니다. 예외 발생 여부). 이러한 테스트에 대한 적절한 용어는

무엇입니까?

통합 테스트? 견고성 테스트?

1

이에 대한 나의 견해는

  1. It't 다음 최대 절전 모드가 작동하는지 아는 것이 거의 불가능, 그것은 예기치 않은 상황이 발생한다는 것입니다 지금은 정의되지 않은 상태로 실행 - 기본적으로 당신이 호출됩니다 UB 세션에서 더 이상의 작업을 수행합니다.

  2. 아이디어 - 인터셉터를 등록하고 그것에 HibernateException이 던져 - Hibernate는 그것을 잡을 수 있기를 바랍니다 : D

  3. 오류 주입은?

+0

1)에 대해서는이 점도 제 이해입니다. 그래서 우리 앱을 더욱 강력하게 만들었습니다. 직접적인 문제는 독립적 인 테스트에서이를 확인하는 방법입니다. 2) 재미있는 소리입니다. 앱 자체를 수정하지 않고도 가능합니다. –

3

흥미로운 것. 가장 좋은 방법은 Hibernate의 소스를 살펴 보는 것입니다.나는 그것을 얻을만큼까지, Session는 다음과 같은 물건을 제외하고, 주변에 많은 상태를 수행하지 않습니다

  • 첫 번째 레벨 캐시 (StatefulPersistenceContext 참조) -이 실제로 트랜잭션 실패 후 파괴 될 수있다;
  • 작업 큐 (ActionQueue 참조) - 수동 플러싱을 수행하는 것이 좋습니다.
  • 이벤트 리스너 - 자신의 인스턴스가 세션을 알고 당신이 눈치 챘을 수도로의 JDBC 예외는 항상 세척 (DefaultFlushEventListener, 더 정확하게하기 위해)하지만, AbstractFlushingEventListener에 잠깐 한눈에 의해 발생 (EventSource 참조) 실제로 세션의 JDBCContextActionQueue과 함께 작동 함을 보여줍니다.

마지막으로 트랜잭션 자체의 롤백은 어떤 식 으로든 세션 상태를 방해하지 않습니다 (JDBCTransaction 참조).

그래서 놀았 던 것처럼, Session은 실제로는 첫 번째 레벨의 캐시가 약간 부정확하다는 점을 제외하고는 잘못된 트랜잭션에서도 살아남습니다. 이 문제를 해결하려면 명시 적으로 상태를 다시 동기화하도록 session.refresh 또는 session.load을 호출하는 것이 좋습니다.

편집 : JDBC 예외를 테스트하는 가장 빠른 방법은 아마도 session.createSQLQuery("something offensive to SQL parser").executeUpdate() - 당신은 완벽한 SQLGrammarException를 얻을 수 있습니다 - 그리고 깨진 거래 =)

0

테스트를 위해 세션의 서브 클래스를 생성합니다. 특정 시나리오에서 예외를 throw하도록 구현하십시오. 테스트 세션을 사용하기 위해 최대 절전 모드를 설정하는 테스트 특정 최대 절전 모드 구성을 사용하십시오.

+0

실제로 HibernateException을 발생 시키지만 Hibernate 세션 자체의 상태에는 영향을 미치지 않습니다. 즉, 이것은 구현 된 모의 세션 일뿐입니다. –

+0

어쩌면 나는 당신이 그 때 찾고있는 무슨을 이해하지 않는다. 최대 절전 모드를 깨뜨린 (예 : 정의되지 않은) 상태로 만들 수있는 안정적인 방법을 찾고 있습니까? 그 다음엔? – james

+0

Hibernate 세션을 깨뜨린 상태로 만드는 신뢰할 수있는 방법을 찾고 있습니다. 따라서 이전 버전의 트랜잭션 (트랜잭션간에 동일한 세션을 재사용 함)이 실패하고 최신 버전 (각 트랜잭션에 대해 새 세션을 얻음))이 시험에 합격했다. –