JPA与EJB分离DAO和Service层

7

这是一个架构问题,我需要关于在项目中集成EJB和JPA的最佳实践方面的帮助。我想要有EJB来完成服务层的工作,包含应用程序的业务逻辑。接下来,我想要有一个DAO层,我的EJB将使用DAO工厂来处理它们,以尽可能分离这两个层次。显然,我不能将我的DAO也作为EJB,因为我不希望它们被自动注入,而是希望通过工厂创建它们。这导致我需要手动创建entitymanager。

Persistence.createEntityManagerFactory("PortalEJB").createEntityManager();

现在...这个调用位于我的抽象JPA DAO中:

public abstract class JPADataAccessorObject<K, E> implements DataAccessorObject<K, E> {
    protected Class<E> entityClass;

    protected EntityManager entityManager;

    protected JPADataAccessorObject(Class<E> pEntityClass) {
        this.entityManager = Persistence.createEntityManagerFactory("PortalEJB").createEntityManager();
        this.entityClass = pEntityClass;
    }

    /* Other DAO functions (update, delete, create) */
}

我认为这是不好的,对吧?我的所有此类具体范围都将拥有一个全新的持久化上下文副本,我会得到奇怪的行为。此外,当我这样做时,我认为我必须在服务层自己管理事务。我正要为此创建方面,例如:
  • 在任何服务层函数/过程之前创建事务
  • (如果出现任何异常,则回滚事务)
  • 在任何服务层函数/过程之后提交事务
所以这里是我的问题:
  • 我应该如何管理EntityManager?
  • 我是否应该有某种JPA实用程序类来管理它,以保护免受多线程影响的一个副本?
  • 如果我犯了严重错误,请提供最佳实践。

Java EE 的哪个版本? - Paul Vargas
我正在使用GlassFish 3.1上的EJB 3.1,Java 1.6,JPA 2.0(EclipseLink)。 - Sylvain Cloutier
1个回答

6

你看过Adam Bien的这篇文章吗:JPA/EJB3 KILLED THE DAODAOS AREN'T DEAD - BUT THEY EITHER COLLAPSED OR DISAPPEARED

另一方面,你可以考虑为服务层设计一个抽象类:

public abstract class AbstractFacade<E extends Serializable, 
                                     PK extends Serializable> {

    private final transient Class<E> entityClass;

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

    protected abstract EntityManager getEntityManager();

    public void create(final E entity) {
        final EntityManager entityManager = getEntityManager();
        entityManager.persist(entity);
    }

    public final E find(final PK id) {
        return getEntityManager().find(entityClass, id);
    }

    // Other common operations

}

还有一个特定的服务

@Stateless
public class UserFacade extends AbstractFacade<User, String> {

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

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

    public UserFacade() {
        super(User.class);
    }

    // Other methods of this service

}

请查看Java EE 6/7:精简版,该内容来自于2012年在旧金山举办的JavaOne会议。


在你的例子中,你的服务层依赖于JPA,这在我看来是一件不好的事情。假设你有用户来自旧的主机,它们将被“转储”到FTP服务器上。使用DAO工厂,你可以拥有FTPUserDAO和JPAUserDAO,它们将是UserDAO的扩展。按照你提出的方式,你将不得不为FTP完全新的服务层。那么,如果你对用户有一个非常复杂的业务算法呢? - Sylvain Cloutier
1
没问题。您可以为您的遗留系统创建一个特定的工厂,并使用CDI进行注入。 - Paul Vargas
我不同意那个观点。在我看来,将DAO和服务分开是更安全的选择。不过你最后提供的链接非常好,视频一开始就介绍了如何搜索JSF JPA教程,并且有一个非常好的教程,正好符合我的需求!!!http://wiki.eclipse.org/EclipseLink/Examples/JPA/JSF_Tutorial - Sylvain Cloutier
99% 的业务逻辑和 1% 的基础架构! - Paul Vargas
2
你让我意识到了一件事,这可能会在我的未来生活中对我有所帮助:最好的解决方案并不总是“按照书本上的方法”来解决。我想尽可能地做到“完美”,但这使得代码对其目的过于复杂。非常感谢你 ;) - Sylvain Cloutier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接