JPA 和 EJB 以及分离的 DAO 和服务层

Posted

技术标签:

【中文标题】JPA 和 EJB 以及分离的 DAO 和服务层【英文标题】:JPA with EJB with separated DAO and Service Layers 【发布时间】:2013-07-01 06:03:02 【问题描述】:

这更像是我目前遇到的架构问题。我需要有关在项目中集成 EJB 和 JPA 的最佳实践方面的帮助。我想要 EJB 来完成服务层的工作,包含我的应用程序的业务逻辑。在此之下,我希望有一个 DAO 层,我的 EJB 将使用 DAO 工厂来尽可能地分离这两个层。知道了这一点,我显然不能将我的 DAO 设为 EJB,因为我不希望它们自动注入,因为我希望它们是通过工厂创建的。这导致我使用手动创建实体管理器

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 的哪个版本? 我在 GlassFish 3.1 上使用 EJB 3.1、Java 1.6、JPA 2.0 (EclipseLink) 【参考方案1】:

你看过 Adam Bien JPA/EJB3 KILLED THE DAO 和 DAOS 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


在旧金山举行的 JavaOne 2012 上的 Java EE 6/7: The Lean Parts 中查看更多信息。

【讨论】:

在您的示例中,您的服务层依赖于 JPA,在我看来,这是一件坏事。假设您有来自旧大型机的用户,该大型机会将他们“转储”到 FTP 服务器上。使用 DAO 工厂,您可以拥有作为 UserDAO 范围的 FTPUserDAO 和 JPAUserDAO。按照您提出的方式,您必须拥有一套全新的 FTP 服务层。现在,如果您的用户有一个非常复杂的业务算法怎么办? 没有问题。您可以为您的遗留系统创建一个特定的工厂并使用 CDI 注入它。 我不同意。以我的拙见,将 DAO 和服务分开是更安全的做法。不过,您的最后一个链接,在视频的开头,这个家伙搜索 JSF JPA 教程并有一个很好的教程,正是我需要的! wiki.eclipse.org/EclipseLink/Examples/JPA/JSF_Tutorial 99% 的业务逻辑和 1% 的基础架构! 你让我意识到一件事可能会在我未来的生活中帮助我:最好的解决方案并不总是“按部就班”的解决方案。我想尽可能地“完美”,但这使得代码过于复杂而无法达到目的。非常感谢;)

以上是关于JPA 和 EJB 以及分离的 DAO 和服务层的主要内容,如果未能解决你的问题,请参考以下文章

带有 JPA/EJB 代码的“分离实体传递给持久错误”

从 JPA/EJB3 持久性上下文中分离实体

java ee EJB中的服务层和dao层

如何在众多 JAR 之间分离我的 Spring JPA 配置?

JPA 认为我正在删除一个分离的对象

取消引用的休眠 (JPA) 实体会发生啥情况?