在很好解耦的服务层和数据访问层中应该如何使用EntityManager? [英] How should EntityManager be used in a nicely decoupled service layer and data access layer?

查看:29
本文介绍了在很好解耦的服务层和数据访问层中应该如何使用EntityManager?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

与我的另一个问题有些相关 应该从数据访问层或接口返回原始 Hibernate 注释的 POJO 吗?,我在创建很好的解耦层方面经验丰富,但不使用 Hibernate 或 J2EE/JPA.我一直在查看文档和教程,并对如何以优雅的方式使用 EntityManger 感到困惑,因为它似乎负责事务(我想在我的服务层执行)和持久性方法(我想要的)保留在数据访问层).我应该在服务层创建它并将其注入数据访问层,还是有更好的方法?下面的伪 java 大致显示了我在想做什么.

Somewhat related to my other question Should raw Hibernate annotated POJO's be returned from the Data Access Layer, or Interfaces instead? , I am experienced in creation of nicely decoupled layers, but not using Hibernate or J2EE/JPA. I have been looking at documentation and tutorials, and am puzzled about how to use the EntityManger in an elegant way, as it seems it is responsible for both transactions (which I want to do at my service layer) and persistance methods (which I want to keep in the data access layer). Should I create it at the service layer and inject it into the data access layer, or is there a better way? The below pseudo-java shows roughly what I'm thinking of doing.

我下面的伪代码基本上取自 hibernate JPA 教程并针对层分离进行了修改,并不反映该产品正在开发以在 EJB 容器 (Glassfish) 中运行.在您的回答中,请提供在 Glassfish 或同等产品中运行的代码的最佳实践和代码示例.

MyService
{

  setup()
  {
       EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory( "Something" ); //is the String you pass in important?
       entityManager = entityManagerFactory.createEntityManager();
  }

  myServiceMethod()
   {
   entityManager.getTransaction().begin();
   MyDao.setEntityManager(entityManagerFactory); 
   MyDao.doSomething();
   MyDao.doSomethingElse();
   entityManager.getTransaction().commit();
   entityManager.close();
   }
 }

MyDao
{
   doSomething()
    {
     entityManager.persist(...); //etc 
    }

}

推荐答案

首先,是否应该使用 DAO 层是自 JPA 和 EntityManager 出现以来一直存在的争论,许多人将其视为 DAO本身.这个问题的答案取决于您正在开发的应用程序类型,但在大多数情况下您会想要:

First off, whether you should use a DAO layer or not is a debate that has been around since the appearance of JPA and the EntityManager which many people consider a DAO itself. The answer to this depends on the type of application you are developing, but in most of the cases you will want to:

  • 使用 JPA 条件或自定义查询.在这种情况下,您可能不想将业务逻辑与查询创建混合在一起.这将导致大型方法并违反单一责任原则.
  • 尽可能重复使用您的 JPA 代码.假设您创建了一个条件查询,用于检索年龄在 40 到 65 岁之间并且在公司工作超过 10 年的员工列表.您可能希望在服务层的其他地方重用这种类型的查询,如果是这种情况,在服务中使用它会使这项任务变得困难.
  • Use JPA criteria or custom queries. In this case you probably don't want to mix your business logic with your query creation. This would lead to large methods and would violate the single responsibility principle.
  • Reuse your JPA code as much as possible. Say you create a criteria query that retrieves a list of employees whose age is between 40 and 65 and have been working in the company for longer than 10 years. You might want to reuse this type of query somewhere else in your service layer, and if that is the case, having it in a service would make this task difficult.

话虽如此,如果您的应用程序中只有 CRUD 操作,并且您认为您可能不需要重用任何 JPA 代码,那么 DAO 层可能有点矫枉过正,因为它只会充当 EntityManager 的包装器,这听起来不对.

That being said, if all you have in your application is CRUD operations and you don't think you might need to reuse any JPA code, a DAO layer is probably something overkill as it will act as a mere wrapper of the EntityManager, which doesn't sound right.

其次,我建议尽可能使用容器管理的事务.如果您使用的是像 TomEE 或 JBoss 这样的 EJB 容器,这将避免大量专用于以编程方式创建和管理事务的代码.

Secondly, I would advise to use container managed transactions whenever possible. In case you are using an EJB container like TomEE or JBoss this would avoid a large amount of code dedicated to programmatically create and manage transactions.

如果您使用的是 EJB 容器,则可以利用声明式事务管理.使用 DAO 的一个示例是将您的服务层组件创建为 EJB 和您的 DAO.

In the case you are using en EJB container, you can take advantage of declarative transaction management. An example of this using DAOs would be to create your service layer components as EJBs and your DAOs too.

@Stateless
public class CustomerService {

    @EJB
    CustomerDao customerDao;

    public Long save(Customer customer) {

        // Business logic here
        return customerDao.save(customer);
    }
}

@Stateless
public class CustomerDao {

    @PersistenceContext(unitName = "unit")
    EntityManager em;

    public Long save(Customer customer) {
        em.persist(customer);
        return customer.getId();
    }

    public Customer readCustomer(Long id) {
            // Criteria query built here
    }

}

在上面的例子中,默认的事务配置是 REQUIRED,这意味着在调用者组件中没有事务的情况下,EJB 将创建一个新的事务.如果调用者已经创建了一个事务 (CustomerService),则被调用的组件 (CustomerDao) 将继承该事务.这可以使用 @TransactionAttribute 注释进行自定义.

In the example above, default transaction configuration is REQUIRED, which means that in absence of a transaction in the caller component, the EJB will create a new transaction. If the caller already creates a transaction (CustomerService) the component being called (CustomerDao) inherits the transaction. This can be customized using the @TransactionAttribute annotation.

如果您没有使用 EJB 容器,我认为您上面的示例可能是等效的.

If you are not using an EJB container, I think your example above would be probably equivalent.

已编辑:为了简单起见,我在上面使用了无接口 EJB,但最好为那些使用接口以制作它们,例如更具可测试性.

EDITED: for the sake of simplicity I have used no-interface EJBs above, but it would be a good practice to use an interface for those in order to make them e.g. more testable.

这篇关于在很好解耦的服务层和数据访问层中应该如何使用EntityManager?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆