it-swarm.com.de

DAO- und Service-Schichten (JPA/Hibernate + Spring)

Ich entwerfe eine neue App, die auf JPA/Hibernate, Spring und Wicket basiert. Der Unterschied zwischen der DAO- und der Service-Schicht ist mir jedoch nicht so klar. Laut Wikipedia ist DAO 

ein Objekt, das eine Zusammenfassung liefert Schnittstelle zu einer Art von Datenbank oder Persistenzmechanismus, der einige bestimmte Vorgänge, ohne Details der Datenbank.

Ich habe mich gefragt, ob ein DAO Methoden enthalten kann, die nicht wirklich viel mit dem Datenzugriff zu tun haben, aber mit einer Abfrage viel einfacher auszuführen sind. Zum Beispiel "eine Liste aller Fluggesellschaften abrufen, die an bestimmten Flughäfen tätig sind"? Es klingt für mich eher wie eine Service-Layer-Methode, aber ich bin nicht sicher, ob die Verwendung von JPA EntityManager in der Service-Ebene ein Beispiel für eine gute Praxis ist.

62
John Manak

Ein DAO sollte Zugriff auf eine einzige related Datenquelle ermöglichen und gibt abhängig von der Komplexität Ihres Geschäftsmodells entweder vollständige Business-Objekte oder einfache Datenobjekte zurück. In jedem Fall sollten die DAO-Methoden die Datenbank etwas genau widerspiegeln.

Ein Service kann eine übergeordnete Schnittstelle bereitstellen, mit der Sie Ihre Geschäftsobjekte nicht nur bearbeiten, sondern überhaupt auf sie zugreifen können. Wenn ich ein Geschäftsobjekt von einem Dienst erhalte, kann dieses Objekt aus verschiedenen Datenbanken (und verschiedenen DAOs) erstellt werden, es könnte mit Informationen versehen sein, die aus einer HTTP-Anforderung stammen. Es kann eine bestimmte Geschäftslogik enthalten, die mehrere Datenobjekte in ein einziges, robustes Geschäftsobjekt konvertiert.

Im Allgemeinen erstelle ich eine DAO, die davon ausgeht, dass sie von jedem Benutzer verwendet wird, der diese Datenbank oder diese Gruppe geschäftsbezogener Daten verwendet. Er ist buchstäblich der Code mit der niedrigsten Ebene neben Auslösern, Funktionen und gespeicherten Prozeduren in der Datenbank. 

Antworten auf spezifische Fragen:

Ich habe mich gefragt, ob eine DAO enthalten Methoden, die nicht wirklich .__ haben. viel mit dem Datenzugriff zu tun, sind aber einfacher mit einer Abfrage ausgeführt?

in den meisten Fällen nein, Sie möchten Ihre kompliziertere Geschäftslogik in Ihrer Serviceschicht, die Zusammenstellung von Daten aus separaten Abfragen. Wenn Sie jedoch Bedenken in Bezug auf die Verarbeitungsgeschwindigkeit haben, kann eine Service-Schicht eine Aktion an ein DAO delegieren, obwohl die Schönheit des Modells beeinträchtigt wird. Dies geschieht auf die gleiche Weise, in der ein C++ - Programmierer Assembler-Code schreibt, um bestimmte Aktionen zu beschleunigen.

Es klingt für mich mehr ein Service-Layer-Methode, aber ich bin mir nicht sicher. Bei Verwendung von JPA EntityManager in der Service-Layer ist ein Beispiel für gutes trainieren?

Wenn Sie Ihren Entitätsmanager in Ihrem Service verwenden, dann denken Sie an den Entitätsmanager als Ihr DAO, denn genau das ist es. Wenn Sie eine redundante Abfrageerstellung entfernen müssen, tun Sie dies nicht in Ihrer Serviceklasse. Extrahieren Sie sie in eine Klasse, die den Entitätsmanager verwendet, und machen Sie diese zu Ihrem DAO. Wenn Ihr Anwendungsfall sehr einfach ist, können Sie die Service-Schicht vollständig überspringen und Ihren Entity Manager oder DAO in Controllern verwenden, da Ihr Service nur noch Anrufe an getAirplaneById() an die DAO-Funktion findAirplaneById() weiterleiten soll.

AKTUALISIERUNG - Um die folgenden Ausführungen zu klären, ist die Verwendung eines Entitätsmanagers in einem Dienst wahrscheinlich nicht die beste Entscheidung in den meisten Situationen, in denen es auch eine DAO-Schicht aus verschiedenen Gründen gibt, die in den Kommentaren hervorgehoben werden. Aber meiner Meinung nach wäre es durchaus vernünftig:

  1. Der Dienst muss mit verschiedenen Datensätzen interagieren
  2. Mindestens ein Datensatz verfügt bereits über ein DAO
  3. Die Service-Klasse befindet sich in einem Modul, das eine gewisse Persistenz erfordert, die einfach genug ist, um keine eigene DAO zu gewährleisten

beispiel.

//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...
   }
}
51
walnutmon

Eines ist sicher: Wenn Sie EntityManager auf der Service-Ebene verwenden, benötigen Sie keine Dao-Ebene (nur eine Ebene sollte die Implementierungsdetails kennen). Abgesehen davon gibt es verschiedene Meinungen:

  • Einige sagen, der EntityManager stellt alle erforderlichen Dao-Funktionen zur Verfügung. Daher injizieren sie EntityManager in die Ebene des Services
  • Andere haben eine traditionelle Dao-Schicht , Die von Schnittstellen unterstützt wird (die Dienstebene Ist also nicht an Implementierungs- -Details gebunden).

Der zweite Ansatz ist eleganter, wenn es um die Trennung von Bedenken geht, und es wird auch den Wechsel von einer Persistenztechnologie zur anderen erleichtern (Sie müssen lediglich die Dao-Schnittstellen mit der neuen Technologie neu implementieren), aber wenn Sie das nicht wissen wird sich ändern, der erste ist einfacher.

Ich würde sagen, wenn Sie ein kleines Projekt haben, verwenden Sie JPA in der Service-Schicht, aber in einem großen Projekt eine dedizierte DAO-Schicht.

14

Dieser article von Adam Bien könnte nützlich sein. 

5
Onur

Normalerweise schreiben Sie Schnittstellen, die den Vertrag zwischen Ihrer Service-Schicht und Ihrer Datenschicht definieren. Sie schreiben dann Implementierungen und dies sind Ihre DAOs.

Zurück zu deinem Beispiel. Angenommen, es gibt viele zu viele Beziehungen zwischen Flughafen und Fluggesellschaft mit einer Tabelle, die airport_id und airline_id enthält, könnte ein Interface vorhanden sein.

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

..und Sie könnten eine Hibernate-Implementierung davon bereitstellen;

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

Sie können auch prüfen, ob Sie eine Liste in Ihrer Airline-Entität haben und die Beziehung mit einer @ManyToMany-JPA-Annotation definieren. Dies würde die Notwendigkeit beseitigen, diese spezielle DAO-Methode insgesamt zu haben.

Vielleicht möchten Sie auch das Abstract Factory-Muster zum Schreiben von DAO-Fabriken betrachten. Zum Beispiel;

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

Durch dieses Muster kann Ihre HibernateDAOFactory ein einzelnes EMF enthalten und einzelne DAO-Instanzen mit EMs versorgen. Wenn Sie nicht auf die Fatory-Route gehen möchten, kann Spring mit DAO-Instanzen mit Abhängigkeitseinspritzung umgehen.

Edit: Einige Annahmen wurden präzisiert.

4
Qwerky

Dao ist ein Datenzugriffsobjekt. Es speichert/aktualisiert/wählt Entitäten in der Datenbank aus. Das Entity-Manager-Objekt wird dafür verwendet (zumindest in open jpa). Sie können auch Abfragen mit diesem Entitätsmanager ausführen. Es ist kein SQL, sondern JPQL (Java Persistence Query Language).

Einfaches Beispiel:

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();
0
Mark Baijens