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

时间:2015-08-12 21:57:47

标签: java session jpa ejb

将在EJB上创建的注入EntityManager传递给将返回Object的方法是否安全,之后,为Web客户端在Web会话上保留该Object使用它?

就像在这个例子中一样: 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
    }

}

之后,我将此服务保留在Web客户端中(使用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类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操作将返回会话上持久保存的服务并尝试使用它。

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

1 个答案:

答案 0 :(得分:1)

我认为在EntityManager中存储SessionMap不是一个好主意。更重要的是,我甚至认为在EJB容器外执行EntityManager操作不是一个好主意。

已阅读JPA中的交易边界?

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

// transaction begins
Service x = service.newServiceX();
// transaction ends

如果您要在事务之外进行一些更新/插入操作,这可能是至关重要的。

现在,当您在事务外部调用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