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

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

问题描述

与我的另一个问题有些相关是否应该从数据访问层或接口返回原始的Hibernate注释POJO?,我有创建良好分离层的经验,但不使用Hibernate或J2EE / JPA。我一直在查看文档和教程,并且对于如何以优雅的方式使用EntityManger感到困惑,因为它看起来对交易(我想在我的服务层中执行)和持久性方法(我想要保留在数据访问层)。我应该在服务层创建它并将其注入到数据访问层,还是有更好的方法?下面的伪Java大致显示了我正在考虑的事情。



编辑:我的伪代码基本上取自休眠JPA教程,但并不反映该产品正在开发中,以便在EJB容器(Glassfish)中运行。在您的回答中,请提供在Glassfish或同等版本中运行的代码的最佳实践和代码示例。

  MyService 
{

setup()
{
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(Something); //是你传递的重要字符串?
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本身。答案取决于您正在开发的应用程序的类型,但在大多数情况下,您会希望: 使用JPA标准或自定义查询。在这种情况下,您可能不希望将业务逻辑与查询创建混合在一起。这将导致大量方法,并违反单一责任原则

  • 尽可能重用您的JPA代码。假设您创建了一个标准查询,该查询检索年龄在40至65岁之间且在该公司工作超过10年的员工列表。您可能希望在您的服务层的其他地方重复使用这种类型的查询,如果是这种情况,在服务中使用这种查询会使这项任务变得困难。



  • 这就是说,如果你的应用程序中只有CRUD操作,并且你不认为你可能需要重用任何JPA代码,那么DAO层可能是有点矫枉过正的,因为它将作为一个单纯的包装的EntityManager,这听起来不对。



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



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

      @Stateless 
    公共类CustomerService {

    @EJB
    CustomerDao customerDao;
    $ b $ public long save(客户客户){

    //商业逻辑
    return customerDao.save(customer);



    @Stateless
    public class CustomerDao {

    @PersistenceContext(unitName =unit)
    EntityManager EM;

    公共长保存(客户客户){
    em.persist(customer);
    返回customer.getId();
    }

    public Customer readCustomer(Long id){
    //在此创建的标准查询
    }

    }

    在上面的示例中,缺省事务配置是REQUIRED,这意味着如果调用者组件中没有事务,则EJB将创建一个新的交易。如果调用者已经创建了一个事务(CustomerService),那么被调用的组件(CustomerDao)将继承该事务。这可以使用 @TransactionAttribute 注释进行定制。

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



    EDITED :为了简单起见,我已经使用了上面的非接口EJB,但是为了让它们使用接口,这将是一个很好的习惯。更可测试。

    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.

    EDIT: My pseudocode below is essentially taken from the hibernate JPA tutorial and modified for the layer separation and does not reflect that the product is being developed to run in an EJB container (Glassfish). In your answers please give best practices and code examples for code running in Glassfish or equivalent.

    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 
        }
    
    }
    

    解决方案

    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:

    • 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.

    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.

    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.

    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
        }
    
    }
    

    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.

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

    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天全站免登陆