2013-06-24 2 views
3

상위 트랜잭션이 롤백 되었기 때문에 REQUIRES_NEW로 주석 된 하위 트랜잭션이 롤백되는 트랜잭션 롤백에 문제가 있습니다. 나는 JTA/JPA가 이러한 트랜잭션을 독립적으로 처리하여 하나의 롤백이 다른 트랜잭션에 영향을 미치지 않도록 생각했기 때문에 의아해합니다. 저는 Java 1.6.0_24, EJB 3.1, GlassFish 3.0.1, JPA 2, MS SQL Server (비 XA) 2008, CMT를 사용하고 있습니다.EJB JTA/JPA CMT 트랜잭션 롤백이 하위 트랜잭션에 영향을 미침

다음 예제는 본질을 보여줍니다. 자체 테네시의 Process EJB는 시작시 감사자를 호출하고 DB 작업을 수행하지만 실패를 결정하고 롤백을 설정 한 다음 완료시 감사자를 호출합니다. 감사 자 EJB는 JPA를 호출하여 별도의 트랜잭션 (REQUIRES_NEW)에 감사 레코드를 작성하며 트랜잭션이 성공하면 제대로 작동합니다. 이 코드는 모든 불필요한 코드가 생략 된 일반적인 감사 구조를 보여줍니다. 제네릭은 문제의 일부로 보입니다.

public interface ErrorDescriptor { 
    public String getName(); 
} 

public interface GenericAuditor<T extends ErrorDescriptor> { 
    public void log(T errorType); 
} 

public abstract class AbstractGenericAuditorImpl<T extends ErrorDescriptor> 
    implements GenericAuditor<T> { 
} 

public enum AuditType implements ErrorDescriptor { 
    BEGIN, FAILED; 
    public String getName() { return name(); } 
} 

public interface Auditor extends GenericAuditor<AuditType> { 
    // The absence of the following 2 lines causes the problem 
    @Override 
    public void log(AuditType errorType); 
} 

@Stateless 
public class AuditorImpl 
    extends AbstractGenericAuditorImpl<AuditType> 
    implements Auditor { 
    @PersistenceContext ("EntityPersistenceManagement") 
    protected EntityManager entityManager; 

    @Override 
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 
    public void log (AuditType e) { 
     ErrorEvent errorEvent = new ErrorEvent(); // entity 
     errorEvent.setName (e.getName()); 
     entityManager.persist (errorEvent); 
    } 
} 

@Stateless 
public class ProcessImpl implements Process { 
    @Resource private EJBContext ejbContext; 
    @EJB private Auditor auditor; 

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 
public void method1() { 
    auditor.log(AuditType.BEGIN); 

    // Perform series of actions including database ops 
    // Takes up to 1 minute 
    // Somethings happen that detects failure 
    ejbContext.setRollbackOnly(); 

    auditor.log(AuditType.FAILED); 
} 
} 

문제는 parent.method1()가 호출 될 때 장애를 결정하고, 세트 롤백까지 조용히 진행한다는 것이다. 이 시점에서 두 번째 감사 호출은 별도의 트랜잭션이 아닌 현재 트랜잭션의 일부인 것처럼 Client의 Transaction Aborted를 발생시킵니다. 또한 첫 번째 감사 호출은 데이터베이스에 데이터를 저장하지 않습니다. 성공하더라도 부모가 커밋 할 때까지 커밋하지 않습니다 (정상입니까?). 이것은 별도의 트랜잭션에서 XA가 아니어야합니다.

트랜잭션이 독립적이라고 주장하는 많은 기사를 읽었지만 this one은 부모가 커밋 할 때까지 중첩 된 트랜잭션이 커밋되지 않으며 부모가 롤백하면 자식도 롤백한다고 제안합니다. 가장 큰 트랜잭션이 커밋 될 때까지 커밋 할 것이 없기 때문에 부분적 또는 상태 작업을 수행하는 방법을 알 수 없습니다.

JPA 구성 - 원래 단일 데이터 소스를 사용했지만 나중에 두 개로 전환되었지만 차이점은 관찰되지 않았습니다. 즉, 롤백이 작동하도록되어 방법 경우

<persistence-unit name="EntityPersistenceManagement" transaction-type="JTA"> 
<jta-data-source>jdbc/app1</jta-data-source> 
<properties> 
    <property name="eclipselink.logging.level" value="INFO"/> 
    <property name="eclipselink.weaving.internal" value="false"/> 
    <property name="eclipselink.weaving" value="false"/> 
    <property name="eclipselink.weaving.fetchgroups" value="false"/> 
    <property name="eclipselink.weaving.changetracking" value="false"/> 
    <property name="eclipselink.weaving.lazy" value="false"/> 
    <property name="eclipselink.weaving.internal" value="false"/> 
    <property name="eclipselink.weaving.eager" value="false"/> 

    <property name="eclipselink.cache.shared.default" value="false"/> 
    <property name="eclipselink.cache.shared" value = "false"/> 
    <property name="eclipselink.query-results-cache" value="false"/> 

    <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/> 
</properties> 

<exclude-unlisted-classes>true</exclude-unlisted-classes> 
<class>org.foo.entities.AppRecord</class> 
<class>org.foo.entities.ErrorEvent</class> 

사람은 말할 수 있습니까? 아마도 이것은 XA에서 다를 수 있습니까?

annotated transaction log이 코드 내의 제어점에 대한 ** 항목을 업로드했습니다.

ADDED :이 second log에는 FINEST에서 EclipseLink 레벨이 있습니다.

편집 : 문제를 일으키는 원인을 정확하게 보여주기 위해 코드를 수정하고 하나의 지속성 관리자 만 반환했습니다.

+0

게시 한 스 니펫이 정확하며 설명 된대로 작동해야합니다. JPA 구성을 제공 할 수 있습니까? (정확한 JTA 구성을 지정했는지 확인하십시오) –

+0

설명대로 작동해야합니다. 동일한 기술을 사용하여 오류를 감사하고 작동했습니다. GF 관리 콘솔에서 tx 관리자 로그를 켜고 어떻게되는지보십시오. – ewernli

+0

답장을 보내 주셔서 감사합니다. 중첩 트랜잭션이 독립적이지 않은지 확인하고 있습니까 (상위 롤백은 하위 롤백을 유발 함)? 이것이 EJB 3.1 스펙의 13.6.2.4와 어떻게 조화를 이루지는 못합니다. JTA/JPA가 중첩 트랜잭션 (플랫 트랜잭션 만)을 지원하지 않지만 아직 존재한다는 것을 계속 읽습니다. –

답변

0

이들은 독립적이어야합니다. 그것은 어딘가에 버그가 될 수 있습니다, 당신은 실패한 거래의 로그를 최고급에 포함시킬 수 있습니까?

+0

주요 질문에 대한 링크 추가 - 로그가 꽤 큽니다. –

+0

필자는 EclipseLink 로그를 가장 훌륭하게 의미했으며, 귀하의 로그에는 EclipseLink 로깅이 포함되어 있지 않습니다. – James

+0

주석이있는 EclipseLink 로그 [here] (http://www.iviz.com/tightwire/jpa-3.txt) –

0

프로세스가 글로벌 트랜잭션 (분산) 내에서 실행 중이므로 하나의 트랜잭션이 실패하면 나머지 트랜잭션이 커밋되지 않습니다. (당신이 설명하는 동작 등)

당신이 쓴 :

. "JPA 구성 - 나는 원래 단일 데이터 소스 을 사용하지만 나중에 두에 를 전환하지만 난 아무 차이가 관찰되지"

문제는 다음과 같습니다. 새 리소스를 추가하면 트랜잭션 관리자가 자동으로 트랜잭션을 배포해야한다고 가정합니다.

"... 2 단계 커밋 전용 트랜잭션이 여러 자원에 걸쳐위한 하나의 자원 - 가치를 추가하지 않습니다. 효율적인 트랜잭션 관리자가 경우 1 단계 커밋 간단한으로 폴백 않습니다 이 단지 을 제안하기보다는 책 Expert One on One J2EE Development without EJB 페이지에서 J2EE 스펙 "

에 필요한 있지만, 단 하나의 자원을 만지지. 233

마지막 로그를 읽었습니다. 트랜잭션이 글로벌이라는 사실이 분명하므로이 동작을 변경해야합니다.

나는 당신의 프레임 워크가 실제로 어떻게 작동하는지 모르겠지만, 로그에 나타나는 클래스에 대해 궁금 : 나는 그것이 com.sun.enterprise.transaction.spi.JavaEETransactionManagerDelegate 인터페이스를 구현하는 것을보고

com.sun.enterprise.transaction.jts.JavaEETransactionManagerJTSDelegate

. the source code's comments 따르면

: JTS와 XA 트랜잭션을 지원 JavaEETransactionManagerDelegate의

구현. 하나의 비 XA 리소스와 로컬 트랜잭션을 지원 JavaEETransactionManagerDelegate의

public class JavaEETransactionManagerJTSDelegate

구현.

public class JavaEETransactionManagerSimplifiedDelegate

난 당신이 프레임 워크를 구성하는 방법을 모른다, 그러나 당신이 다른 구현 (JavaEETransactionManagerSimplifiedDelegate가) 귀하의 경우에 사용되어야 함을 말해 필요가있을 것으로 보인다.

+0

제안 해 주셔서 감사합니다. 나는 원래이 문제를 하나의 비 XA 데이터 소스와 MySQL 하에서 관찰했지만, 확인을 위해 그 조건을 다시 테스트 할 것이다. –

+0

Retest는 동일한 동작을하며 트랜잭션 로그는 모든 트랜잭션이 동일한 ID를 가지고 있음을 보여줍니다. –

+0

나는 그것이 너무 길어서 의견을 말하려고 노력했다. 그래서 대답을 수정했다. –

0

EJB가 중첩 된 트랜잭션을 지원하지 않지만 EclipseLink (GlassFish)가 문제를 설명 할 수 있다는 것을 의미하는 여러 참조를 발견했습니다.

EJB 3.1 Spec 섹션 13.1.2는 명확하게 거래가 일정하고 중첩 된 거래가 없음을 명시합니다. 15.6.1.2 절에서는 호환 컨테이너가 중첩 트랜잭션을 사용해서는 안된다. 13.6.2.4 절에서는 REQUIRES_NEW가 현재 트랜잭션을 일시 중단하고 두 번째 트랜잭션이 커밋 된 후에 다시 시작한다고 말합니다.

JPA/JTA WikiBooks "중첩 트랜잭션"상태에서 다시 지원되지 않으며 내가 보는 동작과 일치하는 포괄적 인 정의를 제공합니다.

The JTA 1.0.1 Spec 섹션 3.1에서는 중첩 트랜잭션이 이 필요하지 않음을 나타내며 가능한 경우를 의미 할 수 있습니다.

그러나이 EclipseLink wiki entry은 중첩 된 커밋이 독립적이 아니고 부모 커밋까지 지연되는 중첩 된 "작업 단위"를 지원함을 보여줍니다. 이것은 실제로 내가 보는 행동과 일치합니다.

따라서 중첩 트랜잭션이 발생하는 경우 부모 롤백시 롤백되지 않는 감사에 대해 격리되고 명확한 커밋을 만드는 방법이 명확하지 않습니다.

1

나는 꽤 비슷한 문제가 있다고 생각한다. 내부 트랜잭션에서는 db로 업데이트했지만 부모 트랜잭션이 완료되면 OptimisticLockException이 발생하여 레코드가 이미 업데이트되었음을 ​​알립니다.

EclipeLink 문서에서 UnitOfWorks에 대해 알면 적어도 (적어도 작동 함 =) 문제를 해결했다고 생각합니다. 문제는 부모 인 UnitOfWork가 RequiresNew 트랜잭션에서 변경 한 사항을 알지 못했다는 것입니다. 부모 트랜잭션 'Parent'가 성공적으로 끝나면 UnitOfWork는 UPDATE에 대한 변경 사항을 포함합니다. 그래서 RequiresNew 호출 후 em.refresh()을 추가했습니다. 내부 거래의 결과 - 적용됨. 학부모 거래 - 성공적으로 마무리되었습니다. 매트

, 당신은 썼다 :

을 내가 중첩 된 트랜잭션을 얻고한다면, 그것은 격리 된 만드는 방법을 분명하지 않다 definate 때 부모 rollsback 롤백되지 않습니다 감사에 대한 커밋합니다.

어쩌면 em.refresh()가 문제를 해결할 수 있습니까? 어쩌면 부모 인 UnitOfWork가 db를 시작 상태로 롤백 할 수 있습니다.

Matt, 많은 참고 자료를 보내 주셔서 감사합니다.

관련 문제