2013-06-11 5 views
5

Ich bin neu bei Spring und ich bin sehr aufgeregt über all die Dinge, die es bietet!Best Practice für echte DAOs mit @Cacheable Annotationen

Momentan versuche ich ein paar DAOs in meinem bestehenden Projekt zu modernisieren. Insbesondere möchte ich meinen alten einfachen JDBC-Code durch Spring Jdbc-Unterstützung ersetzen und Spring's transparentes Caching einführen.

  1. Erste Frage: bin ich richtig, dass die DAO-Schicht ist der richtige Ort @Cacheable Anmerkungen hinzufügen? Oder machen Sie das in der Business-Schicht?

  2. Ich kann alle einfachen Beispiele folgen, die im Netz zu finden sind. Wenn es jedoch um mehr zu realen Welt Code kommt, ich stecken bleiben:

Insbesondere habe ich mehrere Methoden, die Instanzen meines Modells Publisher zurückzukehren. In meinen manuellen Cache-Implementierungen habe ich immer sichergestellt, dass nur eine Instanz zwischengespeichert und für die verschiedenen getPublisher()-Methoden abgerufen wird. Mit der Verwendung von @Cacheable und dem Versuch, Caching innerhalb des DAO zu kapseln, habe ich jedoch das Problem, dass die Annotation nicht für lokale Methodenaufrufe funktioniert (wegen Proxy).

Hier ist mein Beispielcode:

@Cacheable("publisherCache") 
public Publisher getPublisher(int publisherId) 
{ 
    String sql = "SELECT * FROM publisher LEFT JOIN publisherContacts USING (publisherId) WHERE publisherId=? ORDER BY publisherContactId ASC"; 
    return getJdbcTemplate().query(sql, publisherResultSetExtractor, publisherId); 
} 

public List<Publisher> findVisiblePublishers() 
{ 
    List<Publisher> publishers = new LinkedList<Publisher>(); 
    for (int publisherId : findVisiblePublisherIds()) 
    { 
     publishers.add(getPublisher(publisherId)); 
    } 
    return publishers; 
} 

@Cacheable(value = "publisherCache", key = "'list'") 
private List<Integer> findVisiblePublisherIds() 
{ 
    String sql = "SELECT publisherId FROM publisher WHERE isVisible='yes' ORDER BY imprintName"; 
    return getJdbcTemplate().queryForList(sql, Integer.class); 
} 

public Publisher findNearestPublisher(String appx) 
{ 
    appx = "%" + appx + "%"; 
    String sql = "SELECT publisherId FROM publisher WHERE publisherName LIKE ? OR imprintName LIKE ? ORDER BY imprintName DESC LIMIT 1"; 
    Integer publisherId = getJdbcTemplate().queryForObject(sql, Integer.class, appx, appx); 
    if (publisherId == null) 
     return null; 
    else 
     return getPublisher(publisherId); 
} 

Das war meine Idee, die, wie gesagt, nicht funktioniert.

Die einzigen Alternativen, die ich jetzt sehen können, sind:

a) Nur die getPublisher(publisherId) Methode Cache und alle anderen Methoden definieren, die Publisher s Rückkehr davon int s (publisherIds) oder Listen zurückzukehren. Dies ist aus API-Sicht nicht natürlich. Als Service- oder Geschäftslogik würde ich erwarten, Instanzen von der DAO zu bekommen, nicht nur IDs.

b) Fügen Sie @Cacheable zu allen Methoden hinzu, duplizieren Sie den Cache und verwenden Sie mehr Arbeitsspeicher als nötig (nehmen wir an, es gibt viele Publisher und diese sind schwere Objekte).

Was ist die beste Praxis rund um diese Must-Be-Pretty-Common Problem? Danke für alle Einsichten.

+0

Besser, zwei Fragen in zwei SO Fragen zu stellen. – Raedwald

+0

Warum cachen Sie nicht das Ergebnis der 'findVisiblePublishers' Methode? Ja, es werden zwei DB-Abfragen ausgeführt, wenn es das erste Mal aufgerufen wird, aber das war's. Ich denke, es ist ein gutes Ziel für das Caching – Mikhail

+0

Danke Mikhail. Weil die Publisher-Objekte für jede Liste von Herausgebern, die ich zurückgebe (und Cache), zwischengespeichert werden. Der oben gezeigte Ansatz mit getPublisher (id) funktioniert nicht. Wenn Sie getPublisher (id) von derselben Klasse aufrufen, wird der Cache nicht gefragt, aber jedes Mal wird eine Datenbankanforderung ausgeführt. Das bedeutet, dass ich zwei Exemplare des gleichen Publishers im Cache, einmal in der Liste und einmal als einzelnes Objekt habe. Wenn ich ähnliche Methoden habe, wird es schlimmer. – marc82ch

Antwort

0

Gemeinsame Muster folgt: Für Persistenz-Ebene verwenden Sie Ruhezustand Zwischenspeicher der zweiten Ebene. Für Service-Layer verwenden Sie @Cacheable, um Dinge wie lange Berechnungen oder Web-Service-Aufruf-Ergebnisse zwischenzuspeichern.

+0

Hallo Anton, danke für deine Antwort. Dies beantwortet einen Teil meiner ersten Frage.Also mache ich es richtig, wenn ich es in der DAO-Schicht mache, wenn ich DB-Anfragen speichern will (ich kann Hibernate/JPA nicht verwenden). Wie auch immer, selbst in der Service-Schicht würde ich das gleiche Problem für Frage 2 haben. Das Verschieben von @Cacheable auf Service-Level löst mein Problem mit doppeltem Caching nicht. – marc82ch