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

发布于 2024-12-11 02:10:42 字数 1129 浏览 0 评论 0原文

与我的其他问题有些相关 应该从数据访问层返回原始 Hibernate 带注释的 POJO,还是从接口返回?,我在创建良好解耦层方面经验丰富,但不使用 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 
    }

}

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 
    }

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一口甜 2024-12-18 02:10:42

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

  • 使用 JPA 标准或自定义查询。在这种情况下,您可能不想将业务逻辑与查询创建混合在一起。这会导致方法过大,并且违反单一职责原则
  • 尽可能重用您的 JPA 代码。假设您创建一个条件查询来检索年龄在 40 到 65 岁之间且在公司工作时间超过 10 年的员工列表。您可能希望在服务层的其他地方重用这种类型的查询,如果是这种情况,将其放在服务中将使这项任务变得困难。

话虽这么说,如果您的应用程序中只有 CRUD 操作,并且您认为可能不需要重用任何 JPA 代码,那么 DAO 层可能有点过头了,因为它仅充当 EntityManager 的包装器,而听起来不对劲。

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

如果您使用 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
    }

}

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

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

已编辑:为了简单起见,我在上面使用了无接口 EJB,但是为这些 EJB 使用接口是一个很好的做法,以便使它们更具可测试性。

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.

夏尔 2024-12-18 02:10:42

通常,您希望将任何持久性代码隔离到 DAO 层。所以服务层甚至不应该知道EntityManager。我认为如果 DAO 层返回带注释的 pojo 就可以了,因为它们仍然是 pojo。

对于事务管理,我建议您查看 Spring ORM。但是,如果您选择不使用 Spring 或其他 AOP 解决方案,您始终可以通过 DAO 公开与事务相关的方法,以便从服务层调用它们。这样做会让你的生活变得更加困难,但选择权在你......

Typically, you would want to isolate any persistence code to your DAO layer. So service layer should not even know about EntityManager. I think it's ok if DAO layer returns annotated pojos since they remain pojos still.

For the transaction management, I suggest that you look at Spring ORM. But if you choose not to use Spring or other AOP solution, you can always expose transaction related methods via your DAO so you call them from the service layer. Doing so will make your life much harder but the choice is yours...

寂寞陪衬 2024-12-18 02:10:42

对于 getItem()、getEmployee() 等简单情况,最好将实体管理器直接注入到服务层,而不是服务方法调用 Dao(其中有实体管理器注入)方法,用户实体管理器返回对象。这太过分了,DAO 只是充当包装器。对于涉及查询和条件的复杂业务逻辑,让服务方法调用与数据库对话的 Dao。

For simple cases like getItem(), getEmployee() etc, better inject the entitymanager directly to the Service layer use in a method instead of Service method calling a Dao (which has entity manager inject into it) method which user entitymanager to return the object. This is overkill and the DAO simply acts as wrapper. For complex business logic involving queries and criterias, let the service method call Dao which talks tot eh DB.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文