我有一个无状态bean,类似于:
@Stateless
public class MyStatelessBean implements MyStatelessLocal, MyStatelessRemote {
@PersistenceContext(unitName="myPC")
private EntityManager mgr;
@TransationAttribute(TransactionAttributeType.SUPPORTED)
public void processObjects(List<Object> objs) {
// this method just processes the data; no need for a transaction
for(Object obj : objs) {
this.process(obj);
}
}
@TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
public void process(Object obj) {
// do some work with obj that must be in the scope of a transaction
this.mgr.merge(obj);
// ...
this.mgr.merge(obj);
// ...
this.mgr.flush();
}
}通常的用法是客户端调用processObjects(.),它实际上不与实体管理器交互。它做它需要做的事情并调用进程(.)为每个对象单独处理。过程的持续时间(.)相对较短,但processObjects(.)可能要花很长时间才能完成所有的事情。因此,我不希望它维持一个开放的事务。我确实需要单独的程序(.)操作在自己的事务中操作。这应该是每一次呼叫的新事务。最后,我想让客户端调用进程(.)的选项保持开放。直接了当。
我尝试过许多不同的事务类型:从不,不支持,支持(在processObjects上)和必需,需要新的(在进程上),但是每次调用merge()时我都会得到TransactionRequiredException。
我已经能够通过将方法分成两个不同的bean来实现它:
@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {
@EJB
private MyStatelessBean2 myBean2;
public void processObjects(List<Object> objs) {
// this method just processes the data; no need for a transaction
for(Object obj : objs) {
this.myBean2.process(obj);
}
}
}
@Stateless
public class MyStatelessBean2 implements MyStatelessLocal2, MyStatelessRemote2 {
@PersistenceContext(unitName="myPC")
private EntityManager mgr;
@TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
public void process(Object obj) {
// do some work with obj that must be in the scope of a transaction
this.mgr.merge(obj);
// ...
this.mgr.merge(obj);
// ...
this.mgr.flush();
}
}但我仍然很好奇是否有可能在一节课上完成这个任务。在我看来,事务管理器只在bean级别运行,即使给单个方法提供了更具体的注释也是如此。因此,如果我标记一个方法来阻止事务开始调用同一实例中的其他方法,那么无论如何标记,也不会创建一个事务?
我使用的是JBoss应用服务器4.2.1.GA,但欢迎/首选非特定的答案。
发布于 2009-02-04 15:46:23
另一种方法是在同一个bean上使用这两种方法,并拥有对自身的@EJB引用!就像这样:
// supposing processObjects defined on MyStatelessRemote1 and process defined on MyStatelessLocal1
@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {
@EJB
private MyStatelessLocal1 myBean2;
public void processObjects(List<Object> objs) {
// this method just processes the data; no need for a transaction
for(Object obj : objs) {
this.myBean2.process(obj);
}
}
@TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
public void process(Object obj) {
// do some work with obj that must be in the scope of a transaction
this.mgr.merge(obj);
// ...
this.mgr.merge(obj);
// ...
this.mgr.flush();
}
}通过这种方式,您实际上强制通过代理的ejb堆栈访问process()方法,从而使@TransactionAttribute生效,并且仍然只保留一个类。呼!
发布于 2010-04-17 22:06:24
马特,你问的问题是一个非常经典的问题,我认为赫瓦尔/帕斯卡的自我参照解决方案很好。这里没有提到更普遍的解决办法。
这是EJB“用户”事务的一个例子。因为您在会话bean中,所以您可以从会话上下文中获取用户事务。下面是您的代码如何处理用户事务:
// supposing processObjects defined on MyStatelessRemote1 and process defined on MyStatelessLocal1
@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {
@Resource
private SessionContext ctx;
@EJB
private MyStatelessLocal1 myBean2;
public void processObjects(List<Object> objs) {
// this method just processes the data; no need for a transaction
for(Object obj : objs) {
this.myBean2.process(obj);
}
}
public void process(Object obj) {
UserTransaction tx = ctx.getUserTransaction();
tx.begin();
// do some work with obj that must be in the scope of a transaction
this.mgr.merge(obj);
// ...
this.mgr.merge(obj);
// ...
this.mgr.flush();
tx.commit();
}
}发布于 2008-12-04 16:32:11
我认为问题是,每个bean都被包装在一个代理中,该代理控制事务行为。当您从一个bean调用到另一个bean时,您将通过该bean的代理进行调用,并且代理可以更改事务行为。
但是,当bean使用不同的事务属性调用自身上的方法时,调用不会通过代理进行,因此行为不会改变。
https://stackoverflow.com/questions/106437
复制相似问题