【问题标题】:DAO and Service layers (JPA/Hibernate + Spring) [duplicate]DAO 和服务层(JPA/Hibernate + Spring)[重复]
【发布时间】:2011-04-22 09:05:59
【问题描述】:

我正在设计一个基于 JPA/Hibernate、Spring 和 Wicket 的新应用程序。 DAO 和服务层之间的区别对我来说并不是那么清楚。根据维基百科,DAO 是

提供抽象的对象 接口到某种类型的数据库或 持久化机制,提供一些 具体操作不暴露 数据库的详细信息。

我想知道 DAO 是否可以包含实际上不需要对数据访问做太多事情但使用查询更容易执行的方法?例如“获取在特定机场运营的所有航空公司的列表”?在我看来,这更像是一种服务层方法,但我不确定在服务层中使用 JPA EntityManager 是否是一个好的实践示例?

【问题讨论】:

    标签: java spring architecture jpa dao


    【解决方案1】:

    DAO 应提供对单个相关数据源的访问,并且根据您的业务模型的复杂程度,将返回完整的业务对象或简单的数据对象。无论哪种方式,DAO 方法都应该更接近地反映数据库。

    服务可以提供更高级别的接口,不仅可以处理您的业务对象,而且可以首先访问它们。如果我从服务中获取业务对象,则该对象可能是从不同的数据库(和不同的 DAO)创建的,它可以用来自 HTTP 请求的信息进行修饰。它可能具有将多个数据对象转换为单个、健壮的业务对象的特定业务逻辑。

    我通常创建一个 DAO,认为它将被任何将使用该数据库或一组业务相关数据的人使用,它实际上是数据库中除触发器、函数和存储过程之外的最低级别代码。

    具体问题的答案:

    我想知道 DAO 是否可以 包含实际上没有的方法 在数据访问方面做很多事情,但 使用查询更容易执行吗?

    在大多数情况下不,您会希望在服务层中使用更复杂的业务逻辑,即来自单独查询的数据组合。但是,如果您关心处理速度,服务层可能会将操作委托给 DAO,即使它破坏了模型的美感,这与 C++ 程序员可能编写汇编代码来加速某些操作的方式非常相似。

    在我看来更像是一个 服务层方法,但我不确定 如果在 服务层就是一个很好的例子 练习?

    如果您要在服务中使用实体管理器,请将实体管理器视为您的 DAO,因为它就是这样。如果您需要删除一些多余的查询构建,请不要在您的服务类中这样做,将其提取到使用实体管理器的类中并将其作为您的 DAO。如果您的用例非常简单,您可以完全跳过服务层并使用您的实体管理器或控制器中的 DAO,因为您的所有服务要做的就是将对 getAirplaneById() 的调用传递给 DAO 的 findAirplaneById()

    更新 - 为了澄清下面的讨论,在大多数情况下,由于 cmets 中突出显示的各种原因,在服务中使用实体管理器可能不是最佳决策。但在我看来,这是完全合理的:

    1. 服务需要与不同的数据集交互
    2. 至少一组数据已经有一个 DAO
    3. 服务类驻留在一个需要一些持久性的模块中,这种持久性足够简单,不能保证它自己的 DAO

    例子。

    //some system that contains all our customers information
    class PersonDao {
       findPersonBySSN( long ssn )
    }
    
    //some other system where we store pets
    class PetDao {
       findPetsByAreaCode()
       findCatByFullName()
    }
    
    //some web portal your building has this service
    class OurPortalPetLostAndFoundService {
    
       notifyOfLocalLostPets( Person p ) {
          Location l = ourPortalEntityManager.findSingle( PortalUser.class, p.getSSN() )
            .getOptions().getLocation();
          ... use other DAO's to get contact information and pets...
       }
    }
    

    【讨论】:

    • 感谢您提供如此详细的答案。我只是想知道:在服务层中同时拥有 DAO 的集合并使用 EntityManager 可以吗?
    • 我不认为这有什么问题,请记住 Bohzo 所说的服务层与持久性无关。如果事情变得不那么简单,我只需要一个使用实体管理器并处理所有实体的 DAO。我从来没有发现DAO特定于实体或表的通用模式有任何用途,我认为DAO应该绑定到数据库,如果类变大,则在明显冗余时重构
    • 好的。我大多看到 DAO 与单个实体/表紧密耦合,并认为解耦将违反良好实践。所以 Qwerky 回答中的 getAirlinesOperatingFrom() 方法没问题?
    • "是否可以同时拥有 DAO 的集合并在服务层中使用 EntityManager?" - 这有什么意义?通过在服务层中使用 JPA,您已经破坏了使用 DAO 接口抽象出持久性技术选择的目的——当然假设这是您拥有 DAO 层的目标。如果这个抽象不是一个目标,那么你真的不需要跳过假装有一个单独的层。
    • @John Manak - 关于 DAO 的实体 1 到 1 我非常不同意,虽然传统智慧确实遵循你的方法,但我会指出 DRY(不要重复你自己),实际上你将有很多类在实体上执行简单的 CRUD 操作,可以通过简单的泛型方法很容易地处理这些操作。我发现课堂爆炸会分散注意力。当您遵循数据库的单一 DAO 时,您将开始看到随着开发的发展,冗余是什么,并且您的 DAO 可以被有机地重构。
    【解决方案2】:

    有一点是肯定的:如果你在服务层使用EntityManager,你就不需要dao层(只有一层应该知道实现细节)。除此之外,还有不同的意见:

    • 有人说 EntityManager 暴露 所有需要的 dao 功能,所以他们 在服务中注入 EntityManager 层。
    • 其他有传统道层 由接口支持(所以服务 层不依赖于实现 详情)。

    第二种方法在关注点分离方面更优雅,它也可以更轻松地从一种持久性技术切换到另一种(您只需使用新技术重新实现 dao 接口),但如果您知道什么都不会改变,第一个更容易。

    我会说,如果您有一个小项目,请在服务层使用 JPA,但在大型项目中使用专用的 DAO 层。

    【讨论】:

    • 在您的示例中,实体管理器是您的 DAO
    • +1。事实上,在大型项目中,服务层应该与持久性机制无关。
    • +1。同意您的 cmets,即第二种方法提供了更清晰的关注点分离。使用第一种方法,你会在服务层看到很多这样的代码:List<Event> result = entityManager.createQuery( "from Event", Event.class ).getResultList(); 现在,如果同样的东西隐藏在 DAO 层后面,服务层只需要一个事件对象列表,而不必处理获取所需对象列表的方式。
    【解决方案3】:

    Adam Bien 的 article 可能有用。

    【讨论】:

      【解决方案4】:

      传统上,您会编写接口来定义服务层和数据层之间的契约。然后您编写实现,这些就是您的 DAO。

      回到你的例子。假设 Airport 和 Airline 之间的关系是多对多的,使用包含 airport_id 和 airport_id 的表,您可能会有一个接口;

      public interface AirportDAO
      {
         public List<Airline> getAirlinesOperatingFrom(Set<Airport> airports);
      }
      

      ..你可能会提供一个 Hibernate 实现;

      public class HibernateAirportDAO implements AirportDAO
      {
         public List<Airline> getAirlinesOperatingFrom(Set<Airport> airports)
         {
            //implementation here using EntityManager.
         }
      }
      

      您还可以考虑在您的 Airline 实体上使用 List 并使用 @ManyToMany JPA 注释定义关系。这将完全消除使用这种特定 DAO 方法的必要性。

      您可能还想研究抽象工厂模式来编写 DAO 工厂。例如;

      public abstract class DAOFactory
      {
         private static HibernateDAOFactory hdf = new HibernateDAOFactory();
      
         public abstract AirportDAO getAirlineDAO();
      
         public static DAOFactory getFactory()
         {
            //return a concrete implementation here, which implementation you
            //return might depend on some application configuration settings.
         }
      }
      
      public class HibernateDAOFactory extends DAOFactory
      {
         private static EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("myPersistenceUnit");
      
         public static EntityManager getEM()
         {
            return emFactory.createEntityManager();
         }
      
         public AirportDAO getAirportDAO()
         {
            return new HibernateAirportDAO();
         }
      }
      

      此模式允许您的 HibernateDAOFactory 保存单个 EMF 并为单个 DAO 实例提供 EM。如果您不想走这条路线,那么 Spring 非常适合通过依赖注入为您处理 DAO 实例。

      编辑:澄清了一些假设。

      【讨论】:

      • 是的,但这不是业务/服务和数据访问层的混合吗?我的具体意思是 getAirlinesOperatingFrom()。还是这是一个好习惯?这是我在这个领域的第一个项目,所以我不太确定
      • 这种工厂方法在 Spring 场景中没有意义。
      • @seanizer 是的,对于 Spring,OP 可能希望将他的 DAO 配置为他的应用上下文的一部分并注入它们。
      • @John Manak 我假设 Airline 和 Airport 之间的关系存在于数据中,例如 JPA @ManyToMany 的表中包含了airline_id 和 airport_id。如果关系不在数据中(例如,必须调用 web 服务),那么这个方法不应该在 DAO 中。
      【解决方案5】:

      Dao 是一个数据访问对象。它在数据库上存储/更新/选择实体。实体管理器对象用于此(至少在 open jpa 中)。您还可以使用此实体管理器运行查询。它不是 sql,而是 JPQL(Java 持久性查询语言)。

      简单示例:

      emf = Persistence.createEntityManagerFactory("localDB");
      em = emf.createEntityManager();
      
      Query q = em.createQuery("select u from Users as u where u.username = :username", Users.class);
      q.setParameter("username", username);
      
      List<Users> results = q.getResultList();
      
      em.close();
      emf.close();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-14
        • 2013-05-16
        • 2012-02-14
        • 2012-01-25
        • 2010-12-27
        • 2013-07-01
        相关资源
        最近更新 更多