我正在创建一个Java EE Web应用程序,它将使用JPA 2 EclipseLink在数据库上运行。我也在使用应用程序管理的实体经理,所以我可以手动设置交易,虽然我不确定一些事情。
初始信息(仅出于此帖的目的,因为有详细信息/设计部分) 我有JPA实体: UserEntity和UserDetailsEntity 在创建新用户时,我必须创建两个链接在一起的实体的实例。
使用向导从Entity类创建JSF页面时,我注意到NetBeans创建了一个AbstractFacade
和一个实现该Facade的Enterprise Java Bean:UserFacade
和UserDetailsFacade
。这些EJB是JPA CRUD操作的基本包装。
问题:
Facade模式真的很有用吗,特别是在我希望在特定事务中组合少量JPA操作的情况下?这种模式对我的设计有好/坏吗?为什么?
如果我在“UserManagement”中有“事务处理”,事务机制是否有效,但是不是直接从事务块中执行.persist而是执行包装器方法:
utx.begin();
userFacade.create(userEntity);
userDetailsFacade.create(userDetailsEntity);
utx.commit();
我不确定EntityManager,我应该有多个实例吗?除了用户身份验证(了解当前登录的用户),我没有看到保留EntityManager的一个实例的原因。我想我可以在每次需要时使用EntityManagerFactory来获取实例。但令我担忧的是这里的表现以及好/坏的设计实践。或者我应该保留一个EntityManager(在配置类中获得并通过Singleton或CDI共享?)
拥有如下结构的好设计:带表格的JSF页面 - > ManagementBean收集信息并将其相应地传递给正确的EJB Bean - > EJB bean将执行业务方法并将信息传递给负责CRUD的Facade EJB - > FacadeEJBs将保留信息。
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);
}
}
}
}
答案 0 :(得分:3)
EntityManager,我应该有多个实例吗?
entityManager就像您当前的数据库会话。所以使用单例来设计真的很糟糕。这不是线程安全的。它将引用(感谢它的关联persistenceContext)保存到从DB获取的所有对象,因此它应该是一个短时间的生活对象。
关于性能:从entityManagerFactory创建一个entityManager非常快。 (另一方面,创建一个entityManagerFactory花费了很多......所以为entityManagerFactory设置一个单例是个好习惯)