2012-05-19 6 views
0

트랜잭션이 EJB에서 어떻게 작동하는지 약간 혼란 스럽습니다. 나는 항상 TransactionAttribute = REQUIRED_NEW가있는 메소드가 끝났을 때 컨테이너 관리 EJB의 모든 트랜잭션 인식 객체가 커밋되거나 롤백 된 것으로 생각했지만, 불행히도 내 경우에는 그렇지 않습니다. 전 제 코드가 없기 때문에 전체 예제를 포함 할 수는 없지만 제가 요구하는 것은 그것이 어떻게 작동해야하는지에 대한 아이디어의 확인 일뿐입니다. 내 머리 위로 나타난 단지에서 내 코드의
만 핵심 포인트 :상태 비 저장 EJB의 트랜잭션 인식 객체

EntityManager em; //injected 
[...] 
public void someEJBMethod() { 
    [...] 
    em.persist(someObject); 
    [...] 
    Session session = JpaHelper.getEntityManager(em).getActiveSession(); 
    [...] 
    session.executeQuery(query, args); 
    [...] 
    if (someCondition) { 
    throw new EJBException(); 
    } 
    [...] 
} 

그리고 내 문제는 em.persist에 의한 넣어지고있는 EJBException가 슬로우되는 데이터베이스 변경을 롤백 할되지만 변경 session.executeQuery에 의한 것입니다 저지른. 예상되는 동작입니까? 내가 글래스 피시 3.1.2을 사용하고
은 EclipseLink가 오라클 데이터베이스 2.3.2

업데이트 (테스트 케이스 추가)
내가 문제를

먼저 데이터베이스 개체를 표시하는 테스트 케이스를 작업 만든 :

<jdbc-connection-pool driver-classname="" datasource-classname="oracle.jdbc.pool.OracleConnectionPoolDataSource" res-type="javax.sql.ConnectionPoolDataSource" description="" name="TxTest"> 
    <property name="User" value="rx"></property> 
    <property name="Password" value="rx"></property> 
    <property name="URL" value="jdbc:oracle:thin:@test:1529:test"></property> 
</jdbc-connection-pool> 
<jdbc-resource pool-name="TxTest" description="" jndi-name="jdbc/TxTest"></jdbc-resource> 
(domain.xml의에서) 데이터베이스 연결의

create table txtest 
(id number not null primary key, 
name varchar2(50) not null); 

create or replace function txtest_create(p_id number, p_name varchar2) return number is 
begin 
    insert into txtest 
    (id, name) 
    values 
    (p_id, p_name); 

    return p_id; 
end; 

정의

의 persistence.xml

<?xml version="1.0" encoding="UTF-8"?> 
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> 
    <persistence-unit name="txTest"> 
     <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> 
     <jta-data-source>jdbc/TxTest</jta-data-source> 
     <class>txtest.TxTest</class> 
    </persistence-unit> 
</persistence> 

세션 빈 (참) txTest가 호출이 server.log에서

@Stateless 
public class TxTestBean implements TxTestBeanRemote, TxTestBeanLocal { 
    private static Logger log = Logger.getLogger(TxTestBean.class.getName()); 

    @PersistenceContext(unitName="txTest") 
    EntityManager em; 

    @SuppressWarnings({ "unchecked", "rawtypes" }) 
    @Override 
    public void txTest(boolean throwException) { 
     TxTest t = new TxTest(); 
     t.setId(1L); 
     t.setName("em.persist"); 
     em.persist(t); 

     Session session = JpaHelper.getEntityManager(em).getActiveSession(); 
     log.info("session : " + String.valueOf(System.identityHashCode(session))); 
     PLSQLStoredFunctionCall call = new PLSQLStoredFunctionCall(); 
     call.setProcedureName("txtest_create"); 
     call.addNamedArgument("p_id", JDBCTypes.NUMERIC_TYPE); 
     call.addNamedArgument("p_name", JDBCTypes.VARCHAR_TYPE, 50); 
     call.setResult(JDBCTypes.NUMERIC_TYPE); 

     ValueReadQuery query = new ValueReadQuery(); 
     query.setCall(call); 
     query.addArgument("p_id"); 
     query.addArgument("p_name"); 

     t = new TxTest(); 
     t.setId(2L); 
     t.setName("session.executeQuery"); 

     List args = new ArrayList(); 
     args.add(t.getId()); 
     args.add(t.getName()); 

     Long result = ((Number)session.executeQuery(query, args)).longValue(); 

     //added to see the state of txtest table in the database before exception is thrown 
     try { 
      Thread.sleep(20000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 

     log.info("result=" + result.toString()); 

     if (throwException) { 
      throw new EJBException("Test error #1"); 
     } 
    } 
} 

항목 :

[#|2012-05-21T12:04:15.361+0200|FINER|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.connection|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|client acquired: 21069550|#] 
[#|2012-05-21T12:04:15.362+0200|FINER|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.transaction|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|TX binding to tx mgr, status=STATUS_ACTIVE|#] 
[#|2012-05-21T12:04:15.362+0200|FINER|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.transaction|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|acquire unit of work: 16022663|#] 
[#|2012-05-21T12:04:15.362+0200|FINEST|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.transaction|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|persist() operation called on: [email protected]|#] 
[#|2012-05-21T12:04:15.363+0200|INFO|glassfish3.1.2|txtest.TxTestBean|_ThreadID=167;_ThreadName=Thread-2;|session : 16022663|#] 
[#|2012-05-21T12:04:15.364+0200|FINEST|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.query|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|Execute query ValueReadQuery()|#] 
[#|2012-05-21T12:04:15.364+0200|FINEST|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.connection|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|Connection acquired from connection pool [read].|#] 
[#|2012-05-21T12:04:15.364+0200|FINEST|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.connection|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|reconnecting to external connection pool|#] 
[#|2012-05-21T12:04:15.365+0200|FINE|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.sql|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;| 
DECLARE 
    p_id_TARGET NUMERIC := :1; 
    p_name_TARGET VARCHAR(50) := :2; 
    RESULT_TARGET NUMERIC; 
BEGIN 
    RESULT_TARGET := txtest_create(p_id=>p_id_TARGET, p_name=>p_name_TARGET); 
    :3 := RESULT_TARGET; 
END; 
    bind => [:1 => 2, :2 => session.executeQuery, RESULT => :3]|#] 
[#|2012-05-21T12:04:15.370+0200|FINEST|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.connection|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|Connection released to connection pool [read].|#] 
[#|2012-05-21T12:04:35.372+0200|INFO|glassfish3.1.2|txtest.TxTestBean|_ThreadID=167;_ThreadName=Thread-2;|result=2|#] 
[#|2012-05-21T12:04:35.372+0200|FINER|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.transaction|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|TX afterCompletion callback, status=ROLLEDBACK|#] 
[#|2012-05-21T12:04:35.372+0200|FINER|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.transaction|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|release unit of work|#] 
[#|2012-05-21T12:04:35.372+0200|FINER|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.connection|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|client released|#] 
[#|2012-05-21T12:04:35.373+0200|WARNING|glassfish3.1.2|javax.enterprise.system.container.ejb.com.sun.ejb.containers|_ThreadID=167;_ThreadName=Thread-2;|EJB5184:A system exception occurred during an invocation on EJB TxTestBean, method: public void txtest.TxTestBean.txTest(boolean)|#] 
[#|2012-05-21T12:04:35.373+0200|WARNING|glassfish3.1.2|javax.enterprise.system.container.ejb.com.sun.ejb.containers|_ThreadID=167;_ThreadName=Thread-2;|javax.ejb.EJBException: Test error #1 

나에게 놀라게 무엇이 대부분이다 이 20 초 동안 txtest 테이블을 확인할 때. 잠자기 기록 (2, "session.executeQuery")이 이미있었습니다.
session.executeQuery가 어떻게 든 작업을 커밋 (전체 트랜잭션이 아닌)하는 것처럼 보입니다.

누군가가이 동작을 설명 할 수 있습니까?

답변

4

JpaHelper.getEntityManager(em).getActiveSession();은 정확히 무엇을해야할지 모르지만 컨테이너 관리 엔티티 관리자를 반환하지 않는 것 같습니다. 정확히 구현 된 방법에 따라 진행중인 (JTA) 트랜잭션에 참여할 수 없습니다.

일반적으로 트랜잭션 리소스는 모두 자동으로 진행중인 JTA 트랜잭션에 참여합니다. 광범위한 거래에서 거래가 진행 중인지 여부를 확인하여 거래를 수행하며, 실제로 거래가 이루어지면 거래에 등록합니다.

EJB에서 REQUIRES_NEW은 'REQUIRES'(기본값) 트랜잭션을 시작할 수있는 유일한 모드가 아니며 클라이언트가 트랜잭션을 시작하지 않은 경우에도 마찬가지입니다.

+0

'JpaHelper.getEntityManager (em) .getActiveSession()'은 엔티티 관리자가 사용하는 'UnitOfWork'와 정확히 똑같은'UnitOfWork' 객체 (로그로 판단)를 반환하는 EclipseLink 전용 메서드입니다. 그래서 지금 내가 정확히 어떻게 작동 하는지를 확인했을 때이 문제를 설명하기 위해 실제 테스트 케이스를 준비하려고합니다. – tlas

1

나는 그것을 해결했다!

EclipseLink는 읽기 쿼리 처리에 읽기 연결 풀을 사용하고 (물론 해당 유형의 풀은 자동 커밋을 사용하거나 전혀 트랜잭션을 사용하지 않음) 데이터 수정 쿼리를위한 기본 연결 풀을 사용한다는 것이 밝혀졌습니다.

ValueReadQuery query = new ValueReadQuery(); 

DataModifyQuery query = new DataModifyQuery(); 

로하고 매력처럼 작동 : 그래서 내가 한 것은 변화했다.

업데이트
DataModifyQuery은 함수의 결과를 얻을 수 없습니다. 수정 된 행 수를 반환합니다. 그래서 나는 다시 ValueReadQuery을 가지고 있지만 모두가 읽기 및 쓰기에 대한 기본 연결 풀을 사용하여이 매개 변수는 알 수

<property name="eclipselink.jdbc.exclusive-connection.mode" value="Always"/> 

persistance.xml으로는 EclipseLink를 구성 매개 변수를 사용했다.

+0

UnitOfWork.beginEarlyTransaction 또는 em.unwrap (JpaEntityManager) .createQuery (plsqlCall)를 사용하여 JPA 쿼리를 얻을 수도 있습니다. – James

+0

답변으로 받아 들여야합니다. – eis

관련 문제