将注入的 EntityManager 传递给 Web 会话持久化对象

Pass Injected EntityManager to a web session persisted object

将在 EJB 上创建的 Injected EntityManager 传递给将 return 对象的方法,然后在 Web 会话上持久化该对象以供 Web 客户端使用它是否安全?

就像这个例子: EJB

@Stateless(mappedName = "MyService")
@LocalBean
public class MyService implements MyServiceLocal {

@PersistenceContext(unitName="primary")
private EntityManager em;

    /**
     * Default constructor. 
     */
    public MyService() {   
    }


    @Override
    public Service newServiceX(User user) {
        return new ServiceX(user,em); // here, passing the EntityManager
    }

}

之后,我将此服务保存在网络客户端中(使用 struts): 基本动作

    public class YAction extends ActionSupport implements SessionAware{
    @Inject
    private MyServiceLocal service;

    public String execute(){
    Service x = service.newServiceX();
    persistInCookie("ServiceX",x);
    }

    public void persistInCookie(String, Object){
    // persist
    }
    }

然后,使用另一个动作: // 另一个

的动作
   class XAction{

   public String useService(){
   getService().doSomething();
   }


   protected Service getService(){
    Service service = (Service) getSessionMap().get("ServiceX");
    return service;
}

}

使用 EntityManager 的 POJO class ServiceX:

public class ServiceX extends Service{

EntityManager em;

public ServiceX(User user, EntityManager em){
this.em = em;
}

public void doSomething(){
// do something with the EntityManager passed by the EJB
}

}

首先,将要调用的操作是将服务持久化到会话中的 Y 操作,接下来,X 操作将 return 服务持久化到会话中并尝试使用它。

我相信 EJB 无状态会话 Bean 可以关闭 My EntityManager 而这个 ServiceX POJO class 不能使用它。这会发生吗?我发现了类似的问题 HERE,但在这个问题中,EntityManager 被传递给了一个助手 class。在我的情况下是不同的,因为我想将这个对象保存在会话 cookie 上,并在以后使用。

我认为将 EntityManager 存储在 SessionMap 中不是一个好主意。而且,我什至认为在 EJB 容器之外执行 EntityManager 操作不是一个好主意。

是否阅读过 JPA 中的事务边界?

默认情况下,EJB 容器使用 CMT(容器管理事务)。在这种情况下,容器使用 entitymanager-per-request 模式,这意味着事务在 MyService 的业务方法之一开始和结束时开始和结束(事务被提交或在 RuntimeException 的情况下回滚)。对于整个事务时间,EntityManager 连接到相同的 PersistenceContext。事务结束后容器关闭 EntityManager 这意味着 EntityManager 与最近的 PersistenceContext:

断开连接
// transaction begins
Service x = service.newServiceX();
// transaction ends

如果您要在事务外执行一些 update/insert 操作,这可能是至关重要的。

现在,当您在事务外调用 EntityManager 操作(如 find)时,对于每个操作,EntityManager 都会创建新的 PersistentContext。这可能会导致一些问题,因为代表相同记录的两个实体将被视为不同的实体:

// each operation occurs in a separate persistence context, and returns 
// a new detached instance
Magazine mag1 = em.find(Magazine.class, magId);
Magazine mag2 = em.find(Magazine.class, magId);
assertTrue(mag2 != mag1);

还有一些要阅读的文章:

Persistent Context

Transactions and Concurrency

Entity Lifecycle Management