DAO 和服务层(JPA/Hibernate + Spring)

发布于 2024-09-26 20:13:23 字数 315 浏览 0 评论 0原文

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

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

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

I'm designing a new app based on JPA/Hibernate, Spring and Wicket. The distinction between the DAO and Service layers isn't that clear to me though. According to Wikipedia, DAO is

an object that provides an abstract
interface to some type of database or
persistence mechanism, providing some
specific operations without exposing
details of the database.

I was wondering whether a DAO could contain methods that don't really have to do much with data access, but are way easier executed using a query? For example "get a list of all airlines that operate on a certain set of airports"? It sounds to me to be more of a service-layer method, but I'm not sure if using JPA EntityManager in the service layer is an example of good practice?

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

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

发布评论

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

评论(5

紫罗兰の梦幻 2024-10-03 20:13:23

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

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

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

具体问题的答案:

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

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

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

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

更新 - 为了澄清下面的讨论,在大多数情况下,在服务中使用实体管理器可能不是最佳决策,因为在大多数情况下还存在 DAO 层,原因如下:的评论。但在我看来,考虑到以下情况,这是完全合理的:

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

A DAO should provide access to a single related source of data and, depending on how complicated your business model, will return either full fledged Business objects, or simple Data objects. Either way, the DAO methods should reflect the database somewhat closely.

A Service can provide a higher level interface to not only process your business objects, but to get access to them in the first place. If I get a business object from a Service, that object may be created from different databases (and different DAO's), it could be decorated with information made from an HTTP request. It may have certain business logic that converts several data objects into a single, robust, business object.

I generally create a DAO thinking that it will be used by anyone who is going to use that database, or set of business related data, it is literally the lowest level code besides triggers, functions and stored procedures within the database.

Answers to specific questions:

I was wondering whether a DAO could
contain methods that don't really have
to do much with data access, but are
way easier executed using a query?

for most cases no, you would want your more complicated business logic in your service layer, the assembly of data from separate queries. However, if you're concerned about processing speed, a service layer may delegate an action to a DAO even though it breaks the beauty of the model, in much the same way that a C++ programmer may write assembler code to speed up certain actions.

It sounds to me to be more of a
service-layer method, but I'm not sure
if using JPA EntityManager in the
service layer is an example of good
practice?

If you're going to use your entity manager in your service, then think of the entity manager as your DAO, because that's exactly what it is. If you need to remove some redundant query building, don't do so in your service class, extract it into a class that utilized the entity manager and make that your DAO. If your use case is really simple, you could skip the service layer entirely and use your entity manager, or DAO in controllers because all your service is going to do is pass off calls to getAirplaneById() to the DAO's findAirplaneById()

UPDATE - To clarify with regard to the discussion below, using an entity manager in a service is likely not the best decision in most situations where there is also a DAO layer for various reasons highlighted in the comments. But in my opinion it would be perfectly reasonable given:

  1. The service needs to interact with different sets of data
  2. At least one set of data already has a DAO
  3. The service class resides in a module that requires some persistence which is simple enough to not warrant it's own DAO

example.

//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...
   }
}
绝對不後悔。 2024-10-03 20:13:23

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

  • 有人说 EntityManager 公开了
    所有需要的 dao 功能,所以他们
    在服务中注入EntityManager
    层。
  • 其他人有传统的 dao 层
    由接口支持(因此服务
    层与实现无关
    细节)。

当涉及到关注点分离时,第二种方法更加优雅,并且它也将使从一种持久性技术切换到另一种更容易(您只需使用新技术重新实现 dao 接口),但如果您知道什么都没有会改变,第一个更容易。

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

One thing is certain: if you use EntityManager on the service layer, you don't need a dao layer (only one layer should know implementation details). Apart from that, there are different opinions:

  • Some say the EntityManager exposes
    all needed dao functionality, so they
    inject EntityManager in the service
    layer.
  • Others have a traditional dao layer
    backed by interfaces (so the service
    layer is not tied to implementation
    details).

The second approach is more elegant when it comes to separation of concerns and it also will make switching from one persistence technology to the other easier (you just have to re-implement the dao interfaces with the new technology), but if you know that nothing will change, the first is easier.

I'd say if you have a small project, use JPA in the service layer, but in a large project use a dedicated DAO layer.

晨与橙与城 2024-10-03 20:13:23

Adam Bien 的这篇文章可能会有用。

This article by Adam Bien might be useful.

删除→记忆 2024-10-03 20:13:23

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

回到你的例子。假设机场和航空公司之间的关系是多对多,并且有一个包含 airport_id 和 Airlines_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.
   }
}

您还可以考虑在航空公司实体上创建一个列表,并使用 @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 实例。

编辑:澄清了一些假设。

Traditionally you would write interfaces that define the contract between your service layer and data layer. You then write implementations and these are your DAOs.

Back to your example. Assuming the relationship between Airport and Airline is many to many with a table containing airport_id and airline_id you might have an interface;

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

..and you might provide a Hibernate implementation of this;

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

You could also look into having a List on your Airline entity and defining the relationship with a @ManyToMany JPA annotation. This would remove the necessity to have this particular DAO method altogether.

You might also want to look into the Abstract Factory pattern for writing DAO factories. For example;

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();
   }
}

This pattern allows your HibernateDAOFactory to hold a single EMF and supply individual DAO instances with EMs. If you don't want to go down the fatory route then Spring is great at handling DAO instances for you with dependancy injection.

Edit: Clarified a couple of assumptions.

长发绾君心 2024-10-03 20:13:23

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();

Dao is a data access object. It does storing/updating/selecting entities on the database. The entity manager object is used for that (at least in open jpa). You can also run query's with this entity manager. It's no sql but JPQL (Java persistence query language).

Simple example:

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