在JPA 2中使用Transactions和Facade

时间:2013-02-16 15:49:10

标签: jpa transactions ejb

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

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

使用向导从Entity类创建JSF页面时,我注意到NetBeans创建了一个AbstractFacade和一个实现该Facade的Enterprise 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页面 - > ManagementBean收集信息并将其相应地传递给正确的EJB Bean - > EJB bean将执行业务方法并将信息传递给负责CRUD的Facade EJB - > FacadeEJBs将保留信息。

  5. 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);
                }
            } 
    }
    
    
    }
    

1 个答案:

答案 0 :(得分:3)

  

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

entityManager就像您当前的数据库会话。所以使用单例来设计真的很糟糕。这不是线程安全的。它将引用(感谢它的关联persistenceContext)保存到从DB获取的所有对象,因此它应该是一个短时间的生活对象。

关于性能:从entityManagerFactory创建一个entityManager非常快。 (另一方面,创建一个entityManagerFactory花费了很多......所以为entityManagerFactory设置一个单例是个好习惯)