Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Hibernate EntityManager应该如何在一个良好解耦的服务层和数据访问层中使用?_Hibernate_Jpa_Data Access Layer_Service Layer_Entitymanager - Fatal编程技术网

Hibernate EntityManager应该如何在一个良好解耦的服务层和数据访问层中使用?

Hibernate EntityManager应该如何在一个良好解耦的服务层和数据访问层中使用?,hibernate,jpa,data-access-layer,service-layer,entitymanager,Hibernate,Jpa,Data Access Layer,Service Layer,Entitymanager,与我的另一个问题有点相关,我有创建良好解耦层的经验,但没有使用Hibernate或J2EE/JPA。我一直在看文档和教程,对如何优雅地使用EntityManger感到困惑,因为它似乎负责事务(我希望在服务层执行)和持久性方法(我希望保留在数据访问层)。我应该在服务层创建它并将其注入数据访问层,还是有更好的方法?下面的伪java大致显示了我的想法 编辑:我下面的伪代码基本上取自hibernate JPA教程,并针对层分离进行了修改,但没有反映出该产品是在EJB容器(Glassfish)中运行的。在

与我的另一个问题有点相关,我有创建良好解耦层的经验,但没有使用Hibernate或J2EE/JPA。我一直在看文档和教程,对如何优雅地使用EntityManger感到困惑,因为它似乎负责事务(我希望在服务层执行)和持久性方法(我希望保留在数据访问层)。我应该在服务层创建它并将其注入数据访问层,还是有更好的方法?下面的伪java大致显示了我的想法

编辑:我下面的伪代码基本上取自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层。所以服务层甚至不应该知道
EntityManager
。我认为DAO层返回带注释的POJO是可以的,因为它们仍然是POJO


对于事务管理,我建议您查看。但是,如果您选择不使用Spring或其他AOP解决方案,则始终可以通过DAO公开与事务相关的方法,以便从服务层调用它们。这样做会让你的生活更加艰难,但是选择是你的……P> >首先,你是否应该使用一个DAO层,这是自JPA的出现和许多人认为是道本身的实体管理者以来一直存在的争论。答案取决于您正在开发的应用程序的类型,但在大多数情况下,您会希望:

  • 使用JPA标准或自定义查询。在这种情况下,您可能不希望将业务逻辑与查询创建混为一谈。这将导致大量的方法,并将违反规则
  • 尽可能重复使用JPA代码。假设您创建了一个条件查询,检索年龄在40到65岁之间且在公司工作超过10年的员工列表。您可能希望在服务层的其他地方重用这种类型的查询,如果是这种情况,在服务中使用它将使此任务变得困难
这就是说,如果您的应用程序中只有CRUD操作,并且您认为可能不需要重用任何JPA代码,那么DAO层可能有点过火了,因为它只是EntityManager的包装器,这听起来不太正确

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

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

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

}
在上面的示例中,需要默认事务配置,这意味着在调用方组件中没有事务时,EJB将创建一个新事务。如果调用方已经创建了一个事务(CustomerService),则被调用的组件(CustomerDao)将继承该事务。这可以使用注释进行自定义

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


编辑:为了简单起见,我没有使用上面提到的接口EJB,但最好为这些EJB使用接口,以使其更易于测试。

对于简单的情况,如getItem()、getEmployee()等,最好将entitymanager直接注入到方法中使用的服务层,而不是调用Dao(将entitymanager注入)方法的服务方法,该方法由用户entitymanager返回对象。这太过分了,DAO只是充当包装器。对于涉及查询和标准的复杂业务逻辑,让服务方法调用与eh DB对话的Dao

整个管理器不是已经是一把刀了吗?它提供了很好的CRUD接口,并且与数据库无关。将事务逻辑作为DAO方法公开似乎是错误的——也许您可以用一个代码示例来说明。我发现您没有使用JTA——这是故意的吗?您正在手动创建实体管理器并使用资源级别事务。你是在Tomcat还是JavaEE服务器上?@PedroKowalski我基本上是从Hibernate教程中偷来的代码。该应用程序实际上将在Glassfish中运行。我将编辑这个问题以寻求帮助:)这将在GlassFish中运行,因此我将编辑这个问题以明确说明这一点。您的示例代码假设一个EJB容器,是吗?是。上面的代码假设一个符合JEE标准的容器,而Glassfish实际上就是。我会选择这个解决方案,所以Gonzalo-你有我的斧头。。。投票我的意思是:-)。您可以稍微修改它,为您的服务提供CRUD操作(即创建GenericCRUDService)。然后,一些明显基于CRUD的服务将没有任何特定的DAO,如果这些服务需要重用一些复杂的查询,那么这些查询可以在单独的类中定义,如Gonzalo所示,或者作为DDD存储库处理。