2017-05-08 3 views
1

나는 edit(E entity) 함수를 하나의 루프로 호출하는 batchEdit(List<E> entity)을 가지고있다. 반면에 각 edit()는 자신의 트랜잭션을 가지므로 실패한 편집은 좋은 편집을 롤백하지 않는다. 그것은 어떤 EJB 경계를 교차하지 않기 때문에EJB에서 여러 트랜잭션을 가져 오는 깨끗하고 표준적인 방법은 무엇입니까?

옵션 this stackoverflow discussion에 따르면 1

@Stateless 
@TransactionManagement(value = TransactionManagementType.CONTAINER) 
public class Service<E> { 

    @Resource 
    private SessionContext context; 

    @Override 
    @TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW) 
    public E edit(E entity) { 
     //edit code 
    } 

    @Override 
    public List<E> bulkEdit(List<E> entities) { 
     for(E entity : entities){ 
      //case 1: Regular edit, Does not create a new transaction! 
      //edit(entity); 

      //case 2: Hacky edit, creates a new transaction 
      context.getBusinessObject(Service.class).editPersistNulls(entity); 
     } 
    } 
} 

@TransactionAttribute이 때문에, 내 경우 1 batchEdit() 전화 edit() 등을 무시 : 저는 현재 그렇게 같이 구현 주석을 달지 않은 경우. case 2의 context.getBusinessObject() 함수를 사용하여 Bean 참조를 가져 오면 TransactionManagement 주석이 작동하지만 실제로 모든 것을 처리하는 것이 이상하게 보입니다.

내가 가진 다른 옵션은 빈 관리 트랜잭션을 변경하는 것입니다

옵션 2 :

@TransactionManagement(value = TransactionManagementType.BEAN) 

그러나 나는 "JPA 매직"잃고 사방 트랜잭션을 관리해야합니다. 우리 팀의 다른 사람들이 그렇게하기를 원하지 않는다고 생각합니다. 이렇게하는 것이 더 좋거나 표준적인 방법이라면, 어떤 통찰력도 인정 될 것입니다.

우리는 OpenJPA와 EJB를 사용하고 있지만 JPA 표준에 가깝도록 노력하고 있습니다.

답변

0

나는 "해키"가 보는 사람의 눈에 들어왔다 고 생각합니다. context.getBusinessObject 정확하게 존재하므로 이런 종류의 작업을 수행 할 수 있습니다.

대안은 두 번째 클래스를 사용하는 것입니다

@Stateless 
public class BulkService<E> { 

    @EJB 
    private Service<E> service; 

    public List<E> bulkEdit(List<E> entities) { 
     for(E entity : entities) { 
      service.editPersistNulls(entity); 
     } 
    } 

} 

큰 개체주의하여 포괄 트랜잭션이 제한 시간을 초과 할 수 있습니다로, 그러나 나열합니다.

Java EE 7 호환 서버 구현을 사용하는 경우 JSR-352 Batch Applications 지원을 고려하십시오.

+0

흥미 롭습니다. 우리는 getBusinessObject 솔루션으로 끝을 맺었습니다. 그것에 관한 유일한 귀찮은 부분은 빈의 클래스 자체가 아니라 빈의 인터페이스가 필요하다는 것입니다. bean의 클래스 자체를 전달하면 "Component has such interface : "라는 결과를 출력하고, 인터페이스를 전달하는 동안은 작동합니다. – GuitarStrum

+0

인터페이스를 모두 제거하면 클래스 이름을 사용할 수 있습니다. 매우 다른 구현을 계획하고 있다면 EJB의 인터페이스 만 사용하십시오. –

+0

우리 팀이 그걸 실행할 것입니다.우리는 아직 수행하지 못한 잠재적 인 테스트를위한 인터페이스를 가지고 있지만, 인터페이스를 전달하는 것은 큰 리팩터링이 될 것입니다. – GuitarStrum

1

EJB를 직접 삽입 할 수 있습니다.

@Stateless 
public class Service<E> { 

    @EJB 
    private Service<E> self; 

    @TransactionAttribute(REQUIRES_NEW) 
    public void edit(E entity) { 
     // ... 
    } 

    @TransactionAttribute(NOT_SUPPORTED) 
    public void bulkEdit(List<E> entities) { 
     for (E entity : entities) { 
      self.edit(entity); 
     } 
    } 
} 

더 나은 것은 @Asynchronous입니다. 더 빠릅니다. 그것은 물론 동일한 트랜잭션에서 유지해야 다른 서비스를 호출 할 수 있습니다로

@Stateless 
public class Service<E> { 

    @EJB 
    private Service<E> self; 

    public void edit(E entity) { 
     // ... 
    } 

    @Asynchronous 
    @TransactionAttribute(REQUIRES_NEW) 
    public void asyncEdit(E entity) { 
     // ... 
    } 

    @TransactionAttribute(NOT_SUPPORTED) 
    public void bulkEdit(List<E> entities) { 
     for (E entity : entities) { 
      self.asyncEdit(entity); 
     } 
    } 
} 

은 또한 잠재적으로 원치 않는 REQUIRES_NEW 트랜잭션 속성에서 무료로 원래 edit() 방법을 유지합니다. @Asynchronous의 경우 모든 통화에 대해 새 트랜잭션이 필요합니다.

+0

비동기 방법을 두 번 (또는 더 자주) 짧은 용어로 호출하면 어떻게됩니까? 오버플로가 발생할 때까지 호출이 스택됩니까? – kaiser

+0

@ 카이저 Nope. 각각은 별도의 스레드에서 실행됩니다. – BalusC

+0

마지막 질문 하나. REQUIRED_NEW를 사용합니다. 호출 함수가 NOT_SUPPORTED를 가지므로 REQUIRED 속성이 동일하지 않습니까? – kaiser

관련 문제