Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Jpa 无状态EJB中的事务感知对象_Jpa_Transactions_Ejb_Eclipselink - Fatal编程技术网

Jpa 无状态EJB中的事务感知对象

Jpa 无状态EJB中的事务感知对象,jpa,transactions,ejb,eclipselink,Jpa,Transactions,Ejb,Eclipselink,我对EJB中的事务是如何工作的有点困惑。我一直认为容器管理EJB中的所有事务感知对象都是在TransactionAttribute=REQUIRED\u NEW的方法完成时提交或回滚的,但不幸的是,我的情况并非如此。我面前没有我的代码,所以我不能包含整个示例,但我要求的只是确认它应该如何工作。 只有我的代码中的关键点才从我的脑海中浮现出来: EntityManager em; //injected [...] public void someEJBMethod() { [...] em.

我对EJB中的事务是如何工作的有点困惑。我一直认为容器管理EJB中的所有事务感知对象都是在TransactionAttribute=REQUIRED\u NEW的方法完成时提交或回滚的,但不幸的是,我的情况并非如此。我面前没有我的代码,所以我不能包含整个示例,但我要求的只是确认它应该如何工作。
只有我的代码中的关键点才从我的脑海中浮现出来:

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引起的更改。 这是预期行为吗?
我在Oracle数据库中使用Glassfish 3.1.2、EclipseLink 2.3.2

更新(添加测试用例)
我已经创建了工作测试用例来展示这个问题

第一个数据库对象:

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)

调用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以某种方式提交了它的工作(但不是整个事务)


有人能解释一下这种行为吗?

我不确定是什么
JpaHelper.getEntityManager(em.getActiveSession()
应该准确地执行此操作,但它似乎不返回容器管理的实体管理器。根据具体的实现方式,这可能不会参与正在进行的(JTA)事务

但通常情况下,事务资源都会自动参与正在进行的JTA事务。大体上,他们是通过检查正在进行的交易中是否存在这样的情况来实现这一点的,如果确实存在这样的情况,他们将自己注册到该交易中


在EJB中,
REQUIRES\u NEW
不是唯一可以启动事务的模式“REQUIRES”(默认设置),在客户端未启动事务时也会这样做。

我不确定是什么
JpaHelper.getEntityManager(em.getActiveSession()
应该准确地执行此操作,但它似乎不返回容器管理的实体管理器。根据具体的实现方式,这可能不会参与正在进行的(JTA)事务

但通常情况下,事务资源都会自动参与正在进行的JTA事务。大体上,他们是通过检查正在进行的交易中是否存在这样的情况来实现这一点的,如果确实存在这样的情况,他们将自己注册到该交易中


在EJB中,
REQUIRES\u NEW
不是唯一可以启动事务的模式“REQUIRES”(默认设置),在客户端没有启动事务时也会这样做。

我已经解决了

事实证明,EclipseLink使用读取连接池来处理读取查询(显然,这种池使用自动提交,甚至根本不使用事务),而默认连接池用于数据修改查询。所以我要做的就是改变:

ValueReadQuery query = new ValueReadQuery();
进入

DataModifyQuery query = new DataModifyQuery();  
它就像一个符咒

更新
DataModifyQuery
不允许获取函数的结果。它返回修改的行数。所以我回到了
ValueReadQuery
,但在persistence.xml中使用了配置参数

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


这个参数告诉EclipseLink使用默认连接池进行读写操作。

我已经解决了这个问题

事实证明,EclipseLink使用读取连接池来处理读取查询(显然,这种池使用自动提交,甚至根本不使用事务),而默认连接池用于数据修改查询。所以我要做的就是改变:

ValueReadQuery query = new ValueReadQuery();
进入

DataModifyQuery query = new DataModifyQuery();  
它就像一个符咒

更新
DataModifyQuery
不允许获取函数的结果。它返回修改的行数。所以我回到了
ValueReadQuery
,但在persistence.xml中使用了配置参数

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


此参数告诉EclipseLink使用默认连接池进行读写操作。

JpaHelper.getEntityManager(em).getActiveSession()
是EclipseLink特定的方法,在本例中返回的
UnitOfWork
对象(根据日志判断)与实体管理器使用的
UnitOfWork
完全相同。所以现在,当您确认它应该按照我预期的方式工作时,我将尝试准备真实的测试用例来说明这个问题。
JpaHelper.getEntityManager(em)。getActiveSession()
是EclipseLink特定的方法,在这种情况下返回
UnitOfWork
对象,它是(根据日志判断)与实体管理器使用的工作单元完全相同。所以现在,当您确认它应该按照我预期的方式工作时,我将尝试准备真实的测试用例来说明这个问题。您还可以使用UnitOfWork.beginEarlyTransaction或em.unwrap(JPAEEntityManager).createQuery(plsqlCall)来获取JPA查询。您还可以使用UnitOfWork.beginEarlyTransaction或em.unwrap(JPAEEntityManager).createQuery(plsqlCall)以获取JPA查询。