2011-05-04 5 views
0

나는 bean을 저장하고, Hibernate를 통해 DB의 다른 bean을 갱신하는 코드를 가지고있다. 뭔가 잘못된 것이 발생하면 (f.ex가 Exception을 시작 함) 두 작업에 대해 롤백을 실행해야하므로 동일한 트랜잭션에서 수행되어야합니다.어떻게 캡슐화를 잃지 않고 트랜잭션을 수행 할 수 있습니까?

public class BeanDao extends ManagedSession { 

public Integer save(Bean bean) { 
    Session session = null; 
    try { 
     session = createNewSessionAndTransaction(); 

     Integer idValoracio = (Integer) session.save(bean); // SAVE 
     doOtherAction(bean);         // UPDATE 

     commitTransaction(session); 

     return idBean; 
    } catch (RuntimeException re) { 
     log.error("get failed", re); 
     if (session != null) { 
      rollbackTransaction(session); 
     } 
     throw re; 
    } 
} 

private void doOtherAction(Bean bean) { 
    Integer idOtherBean = bean.getIdOtherBean(); 
    OtherBeanDao otherBeanDao = new OtherBeanDao(); 
    OtherBean otherBean = otherBeanDao.findById(idOtherBean); 
    . 
    . (doing operations) 
    . 
    otherBeanDao.attachDirty(otherBean) 
} 
} 

문제는 다음과 같습니다

session.save(bean) 

오류가 실행이 경우

, 그때, AssertionFailure를 얻을 수 있기 때문에 함수 doOtherAction (즉,이 프로젝트의 다른 부분에 사용) 사용 예외가 발생한 후 세션이 throw됩니다.

내가 처음 생각한 것은 함수 doOtherAction의 코드를 추출한 것이지만 동일한 코드가 중복되어 있으며이를 수행하는 데 가장 좋은 방법으로 보이지 않습니다.

리팩토링하는 가장 좋은 방법은 무엇입니까?

답변

0

DAO, 서비스 또는 기타 비즈니스 논리 클래스보다 한 수준에서 트랜잭션을 관리하는 것이 일반적입니다. 비즈니스/서비스 로직을 기반으로하는 한 가지 방법으로 한 트랜잭션에서 두 번의 DAO 작업을 수행하고, 다른 트랜잭션에서는 두 번의 DAO 작업을 수행 할 수 있습니다.

0

저는 Declarative Transaction Management에 대한 큰 팬입니다. GlassFish 또는 JBoss와 같은 Application Server을 사용하고 케이크는 Spring으로 쉽게 처리 할 수 ​​있습니다. 비즈니스 메서드에 @TransactionAttribute(REQUIRED) 주석을 달거나 (기본값으로 설정 될 수도 있음) 두 DAO 메서드를 호출하면 원하는 것을 정확히 얻을 수 있습니다. 모든 것이 한 번에 커밋되거나 예외 위로 롤백됩니다. 이 솔루션은 거의 느슨하게 결합되어 있습니다.

0

다른 것들은 현재 일반적인 관행을 설명하기에 적절하다는 것입니다.

하지만 현재의 실습에 도움이되지는 않습니다.

두 가지 새로운 DAO 방법을 만들어야합니다. CreateGlobalSession 및 CommitGlobalSession과 같은.

이러한 작업은 현재 작성 및 커밋 루틴과 동일합니다.

차이점은 "전역"세션 변수를 설정한다는 것입니다 (대부분 ThreadLocal에서 가장 잘 수행됩니다). 그런 다음이 글로벌 세션이 이미 존재하는지 확인하도록 현재 루틴을 변경합니다. create가 글로벌 세션을 발견하면 간단히 반환하십시오. 커밋이 글로벌 세션을 감지하면 아무 일도하지 않습니다.

지금 당신이 그것을 사용하고자 할 때이 작업을 수행 :

try { 
    dao.createGlobalSession(); 
    beanA.save(); 
    beanb.save(); 
    Dao.commitGlobalSession(); 
} finally { 
    dao.rollbackGlobalSession(); 
} 

오류가 있다면 당신은 당신의 글로벌 세션을 재설정 할 수 있도록 try 블록에서 과정을 포장해야합니다. 다른 기술이 모범 사례로 간주하고 이상적 어느 날 그런 식으로 진화 할 수 있지만

, 이것은 당신이 좀 더 세 이상의 새로운 방법과 기존의 두 방법을 변화하는 고비 극복 할 것이다. 그 후 나머지 코드는 그대로 유지됩니다.

+0

공유 세션/트랜잭션 (안티) 패턴을 사용하는 많은 코드를 유지 관리해야하는 사람으로, 일부 구성 작업을 피하기 위해 개발 단계에서 사용하는 것이 현명하지 않다고 말할 수 있습니다 리팩토링. 이 솔루션은 유지 보수 비용을 높이는 경향이 있습니다. 어느 시점이나 다른 누군가가 트랜잭션을 커밋하는 것을 잊어 버리거나, 세션이 누출되거나, 예약 된 작업에 문제가 있거나 응용 프로그램을 클러스터링하는 등의 문제가 있습니다. 완전히 실용적인 관점에서 볼 때 나는 "이상적인" "장기적으로 싸다는 것이 입증되었습니다". –

+0

방금 ​​말한 내용을 수정하십시오. 공유 세션/트랜잭션은 모든 곳에서 빠르게 복사되고 붙여 넣기되는 일종의 해결 방법이며, 조만간 프로젝트에서 트랜잭션 관리를위한 일종의 표준이됩니다. 괴물을 만들지 마십시오. –

+0

@Anthony, 물론, 여기에 문제가 있습니다. 이 경우는 실제 트랜잭션에만 필요하며,이 경우에는 드문 경우입니다. 따라서 DAO의 정상적인 메커니즘은 여전히 ​​존재합니다 (당연히 누설 될 수 있음). 그런 다음 다른 사람이 나중에 다른 멀티 - 빈 트랜잭션을 추가하기를 원한다면 패턴을 유지하면서이 원본 코드를 잘라내어 붙일 가능성이 높습니다. 허락하면, 부작용. 그러나 그는 또한 자신의 코드가 서버에 있는지, 클라이언트에 있는지 또는 무엇이 있는지에 대해서는 언급하지 않았습니다. 그가 제안한 것을하기 위해 그는 EJB 나 Spring 또는 다른 프레임 워크가 필요합니다. 그에게는 실용적이지 않을 수도 있습니다. –

관련 문제