0

トランザクションがEJBでどのように機能するかについては少し混乱しています。TransactionAttribute = REQUIRED_NEWのメソッドが終了すると、コンテナ管理の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();
  }  
  [...]
}  

そして私の問題は、EJBExceptionがスローされると、em.persistによって引き起こされたデータベースの変更はロールバックされますが、session.executeQueryによって引き起こされた変更はコミットされるということです。期待される動作ですか?
Glassfish 3.1.2、EclipseLink2.3.2をOracleデータベースで使用しています

更新(テストケースを追加)
問題を示すために動作するテストケースを作成しました

最初のデータベースオブジェクト:

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;

データベース接続の定義(domain.xmlから)

<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>  

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>  

セッションBean:

@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");
        }
    }
}  

txTest(true)が呼び出されたときのserver.logからのエントリ:

[#|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: txtest.TxTest@11b9605.|#]
[#|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

2 に答える 2

4

正確に何をすべきかJpaHelper.getEntityManager(em).getActiveSession();はわかりませんが、コンテナ管理のエンティティマネージャが返されない可能性があります。正確に実装されている方法によっては、これは進行中の(JTA)トランザクションに参加しない場合があります。

ただし、通常、トランザクションリソースはすべて、進行中のJTAトランザクションに自動的に参加します。大まかに言えば、進行中のトランザクションにそのようなものがあるかどうかをチェックすることによってこれを行い、実際にある場合は、このトランザクションに登録します。

EJBではREQUIRES_NEW、トランザクションを開始できるモードは「REQUIRES」(デフォルト)だけではありません。これは、クライアントがトランザクションを開始しなかった場合にも実行されます。

于 2012-05-19T21:09:55.820 に答える
1

解決しました!!!

EclipseLink は、読み取りクエリを処理するために読み取り接続プールを使用し (そして、明らかにその種類のプールは自動コミットを使用するか、トランザクションをまったく使用しません)、データ変更クエリにはデフォルトの接続プールを使用することが判明しました。だから私がしなければならなかったのは、変更することでした:

ValueReadQuery query = new ValueReadQuery();

の中へ

DataModifyQuery query = new DataModifyQuery();  

そしてそれは魅力のように機能します。

更新
DataModifyQueryでは、関数の結果を取得できません。変更された行の数を返します。だから私は戻ってきましValueReadQueryたが、persistance.xmlで設定パラメータを使用しました

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

このパラメータは、読取りと書込みの両方にデフォルトの接続プールを使用するようEclipseLinkに指示します。

于 2012-05-21T11:33:14.080 に答える