1

我正在创建一个 Java EE Web 应用程序,它将使用 JPA 2 EclipseLink 在数据库上运行。我也在使用应用程序管理的实体管理器,所以我可以手动设置事务,尽管我不确定一些事情。

初始信息(仅出于本文的目的,因为有细节/设计部分)我有 JPA 实体:UserEntity 和 UserDetailsEntity 在创建新用户时,我必须创建两个实体的实例,它们链接在一起。

在使用向导从实体类创建 JSF 页面时,我注意到 NetBeans 创建了一个AbstractFacade和一个实现该外观的企业 Java Bean:UserFacadeUserDetailsFacade. 这些 EJB 是 JPA CRUD 操作的基本包装器。

问题:

  1. Facade 模式真的有用吗,尤其是在我想在特定事务中组合几个 JPA 操作的情况下?这种模式对我的设计是好还是坏?为什么?

  2. 如果我有“UserManagement 中的事务进程”,事务机制是否会起作用,但不是直接从事务块中执行 .persist,而是执行包装器方法:

        utx.begin();
        userFacade.create(userEntity);
        userDetailsFacade.create(userDetailsEntity);
        utx.commit();
    
  3. 我不确定 EntityManager,我应该有多个实例吗?除了用户身份验证(了解当前登录的用户)之外,我看不到保留一个 EntityManager 实例的理由。我想我可以在每次需要时使用 EntityManagerFactory 来获取实例。但我关心的是这里的性能和好的/坏的设计实践。或者我应该保留一个 EntityManager(在配置类的某个地方获得并通过 Singleton 或 CDI 共享?)

  4. 具有类似以下结构的 JSF Pages -> ManagementBean 收集信息并将其相应地传递给正确的 EJB Bean -> EJB bean 将执行业务方法并将信息传递给负责 CRUD 的 Facade EJB -> FacadeEJB 将坚持信息。

AbstractFacade 的代码:(草稿)

public abstract class AbstractFacade<T> {
private Class<T> entityClass;

public AbstractFacade(Class<T> entityClass) {
    this.entityClass = entityClass;
}

protected abstract EntityManager getEntityManager();

public void create(T entity) {
    getEntityManager().persist(entity);
}

public void edit(T entity) {
    getEntityManager().merge(entity);
}

public void remove(T entity) {
    getEntityManager().remove(getEntityManager().merge(entity));
}

public T find(Object id) {
    return getEntityManager().find(entityClass, id);
}

public List<T> findAll() {
    javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
    cq.select(cq.from(entityClass));
    return getEntityManager().createQuery(cq).getResultList();
}

public List<T> findRange(int[] range) {
    javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
    cq.select(cq.from(entityClass));
    javax.persistence.Query q = getEntityManager().createQuery(cq);
    q.setMaxResults(range[1] - range[0]);
    q.setFirstResult(range[0]);
    return q.getResultList();
}

public int count() {
    javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
    javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
    cq.select(getEntityManager().getCriteriaBuilder().count(rt));
    javax.persistence.Query q = getEntityManager().createQuery(cq);
    return ((Long) q.getSingleResult()).intValue();
}

}

UserFacade 的代码(草稿,因为我将修改这个类以从工厂中检索 EntityManagers 而不是使用 CDI):

@Stateless
public class UserEntityFacade extends AbstractFacade<UserEntityEntity> {
@PersistenceContext(unitName = "FMSBetaPU")
private EntityManager em;

@Override
protected EntityManager getEntityManager() {
    return em;
}

public TestEntityFacade() {
    super(TestEntity.class);
}

}

UserManagement EJB 代码(草稿)

@Stateless
public class UserManagement {

@Resource
private UserTransaction utx;
@EJB
private UserEntityFacade userFacade;
@EJB
private UserDetailsEntityFacade userDetailsFacade;

public void createUser(int id, String name)
{
    UserEntity userEntity = new UserEntity(id);
    UserDetailsEntity userDetailsEntity = new UserDetailsEntity(name);
    try {
            utx.begin();
            userFacade.create(userEntity);
            userDetailsFacade.create(userDetailsEntity);
            utx.commit();
        } 
    catch (Exception e) {
            try {
                utx.rollback();
            } catch (IllegalStateException ex) {
                Logger.getLogger(UserManagement.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SecurityException ex) {
                Logger.getLogger(UserManagement.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SystemException ex) {
                Logger.getLogger(UserManagement.class.getName()).log(Level.SEVERE, null, ex);
            }
        } 
}


}
4

1 回答 1

3

EntityManager,我应该有多个实例吗?

entityManager 就像您当前的数据库会话。所以使用单例是非常糟糕的设计。它不是线程安全的。它持有对从数据库中获取的所有对象的引用(感谢它关联的 persistenceContext),因此它应该是一个短时对象。

关于性能:从 entityManagerFactory 创建 entityManager 非常快。(另一方面,创建 entityManagerFactory 的成本很高......所以最好为 entityManagerFactory 设置一个单例)

于 2013-02-16T15:58:48.513 回答