2010-03-15 21 views
7

Korrigieren Sie mich, wenn etwas nicht stimmt.DAO, Spring und Hibernate

Wenn wir Spring DAO für ORM-Vorlagen verwenden, haben wir bei Verwendung des @Transactional-Attributs keine Kontrolle über die Transaktion und/oder Sitzung, wenn die Methode extern aufgerufen wird, nicht innerhalb der Methode.

Lazy loading spart Ressourcen - weniger Abfragen an die db, weniger Speicher, um alle im App-Speicher abgerufenen Sammlungen zu behalten.

Also, wenn Lazy = false, dann wird alles abgerufen, alle zugeordneten Sammlungen, das ist nicht effektiv, wenn 10.000 Datensätze in einem verknüpften Set sind.

Jetzt habe ich eine Methode in einer DAO-Klasse, die mir ein Benutzerobjekt zurückgeben soll. Es enthält Auflistungen, die verknüpfte Tabellen der Datenbank darstellen. Ich muss ein Objekt nach ID abrufen und dann seine Sammlungen abfragen.

Hibernate "fehlgeschlagen zu initialisieren eine Sammlung" Ausnahme tritt auf, wenn ich versuche, auf die verknüpfte Sammlung zuzugreifen, die diese DAO-Methode zurückgibt.

Erklären Sie bitte, was ist ein Workaround hier?

Update: Alles klar, lass mich dich das fragen. Da DAO eine abstrakte Ebene ist, soll eine Methode "getUserById (Integer id)" ein Objekt zurückgeben.

Was, wenn in einigen Fällen ich diese verknüpften Sammlungen des Benutzerobjekts benötige und in anderen Situationen brauche ich diese Sammlungen.

Gibt es nur zwei Möglichkeiten: 1) verzögertes Laden = false 2) erstellen, um verschiedene Methoden: getUserByIdWithTheseCollections(), getUserByIdWithOtherCollections() und innerhalb dieser Methoden Ihren Ansatz verwenden?

Ich meine, gibt es nur 2 Möglichkeiten und nichts besseres?

Update 2: Erklären Sie bitte, was würde mir die ausdrückliche Verwendung von SESSIONFACTORY geben? Wie sieht es in der Praxis aus? Wir erstellen eine Instanz des DAO-Objekts und injizieren sie dann mit der Sitzungsfactory. Dies würde bedeuten, dass zwei aufeinanderfolgende Methodenaufrufe von an DAO innerhalb derselben Transaktion ausgeführt werden. Es scheint mir, dass DAO unabhängig von den Klassen ist, die es nutzen!

Die Logik und die Transaktionen sind in DAO gekapselt, richtig?

Antwort

6

Sie können die verknüpfte Sammlung in der Transaktion erhalten, es zu laden, während Sie noch in der Transaktion sind:

User user = sessionFactory.getCurrentSession().get(User.class, userId); 
user.getLinkedCollection().size(); 
return user; 

Wie BalusC hervorgehoben hat, Sie Hibernate.initialize() statt size() verwenden können. Das ist viel sauberer.

Wenn Sie dann eine solche Entität zurückgeben, wird das Lazy-Feld bereits initialisiert.

Antwort auf Ihre PS - verwendet Transaktionen auf Service-Level (statt DAO) Ebene möglich? Es scheint so, als ob jeder DAO-Aufruf in einer separaten Transaktion eine Verschwendung ist (und möglicherweise inkorrekt ist).

+0

@Konrad Garus meine Nachschrift der Frage Bitte beachten Sie, hier ist der Text weniger lesbar, so frage ich Sie da. – EugeneP

+0

@EugeneP Siehe aktualisierte Antwort. –

5

Ich finde, dass es am besten ist, @Transactional in der Service-Schicht und nicht in der DAO-Schicht zu platzieren. Ansonsten befinden sich alle Ihre DAO-Aufrufe in getrennten Ruhezustands-Sitzungen - all diese Objekt-Gleichheits-Dinge funktionieren nicht.

+1

Dies ist ein guter Weg, um mit SpringDAO umzugehen. –

1

Meiner Meinung nach beste Weg, um dieses Problem zu lösen, wird die Anwendung in einem Sitzung-pro-Anfrage-Modell entwerfen. Wenn Sie dann sogar ein Objekt aus DAO nehmen, bis Ihr OSIV-Muster funktioniert, können Sie das Objekt sicher irgendwo in der Anwendung verwenden, sogar in Ansichten, ohne sich um dieses Zeug zu kümmern. Dies ist wahrscheinlich eine bessere Lösung, die jene vorgeschlagen, weil:

  1. Hibernate.initialize() oder Größe ist eine sehr künstliche Abhilfe - was ist, wenn Sie Benutzer mit unterschiedlichen Sammlung initialisiert haben wollen, würden Sie eine andere Methode für das Erhalten Benutzer schreiben?
  2. Dienstschicht Transaktionsmodell ist in Ordnung, aber das gleiche Problem kommt, wenn Sie Objekt aus der Service-Schicht extrahierte bekommen es in der Steuerung zu verwenden oder Ansicht
1

Sie etwas tun könnte wie folgt vor:

public User getByUserId(Long id, String ... fetch) { 
    Criteria criteria = createCriteria(); 

    if (fetch != null) { 
     for (String fieldName : fetch) { 
      criteria.setFetchMode(fieldName, FetchMode.JOIN); // fetch these fields eagerly 
     } 
    } 
    return criteria.add(Restrictions.eq("id", id)).list(); 
} 
Verwandte Themen