0

고객을 타사 시스템에 프로비저닝하는 일반적인 엔터프라이즈 애플리케이션을 개발했습니다. 이 시스템에는 특정 고객에 대해 하나의 스레드 만 작동 할 수 있다는 제한이 있습니다. 그래서 우리는 @Singleton으로 구성된 간단한 잠금 메커니즘을 추가했습니다. 여기에는 현재 진행중인 고객 번호 Set이 포함되어 있습니다. 프로비저닝을위한 새로운 요청이있을 때마다 먼저 Set을 확인합니다. cusotomerId가 있으면 기다리고 그렇지 않으면 Set에 처리를 추가합니다.별도의 EJB 메소드로 트랜잭션 시작/종료

최근에이 응용 프로그램이 클러스터에 배포되므로이 잠금 방식이 더 이상 유효하지 않다고 결정되었습니다. 잠금을 위해 DB를 사용하는 솔루션을 찾았습니다. customerIds를 포함 할 단일 열이있는 테이블을 만들었습니다 (고유 제약 조건도 있습니다). 새로운 프로비저닝 요청이있을 때 우리는 트랜잭션을 시작하고 SELECT FOR UPDATE으로 customerId를 가진 행을 시도하고 잠급니다 (customerId가 아직 존재하지 않으면 삽입합니다). 그런 다음 고객 프로비저닝을 시작하고 완료되면 트랜잭션을 커밋합니다. 개념은 작동하지만 트랜잭션에 문제가 있습니다. 현재 CustomerLockadd()remove() 개의 메소드가 있으며 Set에서 customerIds를 추가 및 삭제합니다. 이 클래스를 빈 관리 트랜잭션이있는 상태 비 저장 EJB로 변환하려고했습니다. add() 메서드는 트랜잭션을 시작하고 행을 잠급니다. remove() 메서드는 트랜잭션을 커밋하여 행을 잠금 해제합니다. 그러나 거래의 시작과 끝은 같은 방법으로 이루어져야합니다. 설명 된 접근법을 사용하는 방법이 있습니까? 아니면 동일한 방법으로 트랜잭션이 시작되고 끝나기 위해 로직을 수정해야합니까?

CustomerLock 클래스 :

@Stateless 
@TransactionManagement(TransactionManagementType.BEAN) 
public class CustomerLock { 

    @Resource 
    private UserTransaction tx; 

    public void add(String customerId) throws Exception { 
     try { 
      tx.begin(); 
      dsApi.lock() 
     } catch (Exception e) { 
      throw e; 
     } 
    } 

    public void remove(String customerId) throws Exception { 
     try { 
      tx.commit(); 
     } catch (Exception e) { 
      throw e 
     } 
    } 
} 

CustomerProvisioner 클래스 발췌 :

public abstract class CustomerProvisioner { 

    ... 

    public void execute(String customerId) { 
     try { 
      customerLock.add(customerId); 

      processing.... 

      customerLock.remove(customerId); 
     } catch (Exception e) { 
      logger.error("Error", e); 
     } 
    } 

    ... 

} 

StandardCustomerProvisioner 클래스 :

@Gimby가 언급 한 바와 같이
@Stateless 
public class StandardCustomerProvisioner extends CustomerProvisioner { 

    ... 

    public void provision(String customerId) { 
     // do some business logic 
     super.execute(customerId); 
    } 
} 
+0

왜 "동일한 방법으로 거래의 시작과 종료가 발생해야합니까?" 마지막으로 블록 BTW에 꽤 이상한 커밋 호출이 있습니다. 모든 것이 잘되면 (아무 예외도 던지지 않음) 트랜잭션을 커밋하고 DB 잠금은 지금까지 사라집니다 (트랜잭션 차원). – user3714601

+0

죄송합니다 ... '마침내'멘토가 아닙니다. :) 코드를 수정했습니다. – goggy

+0

Excerpt = snippet, 대개 자세한 내용이 충분하지 않습니다. "CustomerProvisioning"이란 무엇입니까? 다른 EJB? – Gimby

답변

0

, 당신은 혼합하지 말아야 컨테이너 관리 및 bean- 관리되는 트랜잭션. StandardCustomerProvisioner에는 "@ TransactionManagement (TransactionManagementType.BEAN)"과 같은 주석이 없기 때문에 컨테이너 관리 트랜잭션을 사용하며 기본적으로 REQUIRED가 필요합니다.

당신은 그것이 작동되도록하는 2 가지 옵션이 있습니다 :

1) (이 주석 ("@TransactionManagement 추가) UserTransaction을 호출하여"@TransactionManagement (TransactionManagementType.BEAN) "을 제거하고

2 CMT

를 실행하려면 TransactionManagementType.BEAN) ")을 StandardCustomerProvisioner에 연결하고이 메서드에서 트랜잭션 마크 업 호출을 사용하므로 모든 호출 된 메서드가 동일한 트랜잭션 컨텍스트를 사용합니다. CustomerLock의 마크 업 전화는 어쨌든 제거해야합니다.

+0

늦게 답변을 드려 죄송합니다. 예,이 거래가 컨테이너에서 어떻게 작동하는지 완전히 오해했습니다. 위의 해결책을 실현하기 위해 몇 가지 의견을 제시 한 후에 만 ​​생각하겠습니다. 나는 방금 약간의 '브레인 스토밍'이 필요하다고 생각한다 :) 답장을 보내 주셔서 감사합니다! 건배 – goggy