2013-06-11 12 views
5

Jestem nowy na wiosnę i jestem bardzo podekscytowany tym, co oferuje!Najlepsza praktyka dla rzeczywistych DAO używających @Cacheable adnotacje

W tej chwili próbuję zmodernizować kilka DAO w moim istniejącym projekcie. W szczególności chcę zamienić mój stary zwykły kod JDBC na obsługę Spring Jdbc i wprowadzić przejrzyste buforowanie Spring.

  1. Pierwsze pytanie: czy mam rację, że warstwa DAO jest właściwym miejscem, aby dodać @Cacheable adnotacje? Czy robisz to w warstwie biznesowej?

  2. Mogę śledzić wszystkie proste przykłady, które można znaleźć w Internecie. Jednak, gdy chodzi o więcej kodu prawdziwy świat, mam utknąć:

Konkretnie mam kilku metod, które zwracają instancji mojego modelu Publisher. W moich ręcznych implementacjach pamięci podręcznej zawsze upewniłem się, że tylko jedna instancja jest buforowana i pobierana dla różnych metod. Jednak przy użyciu @Cacheable i próbę enkapsulacji pamięci podręcznej w ramach DAO, mam problem, że adnotacja nie działa dla lokalnych wywołań metod (z powodu proxy).

Oto mój przykładowy kod:

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

To był mój pomysł, który jak powiedział, nie działa.

Jedyne alternatywy widzę teraz to:

a) buforować jedynie metodę getPublisher(publisherId) i zdefiniować wszystkie inne metody, które zwracają Publisher s, aby powrócić int s (publisherIds) lub jego list. To nie jest naturalne z punktu widzenia API. Jako logikę usług lub biznesu oczekiwałbym, że otrzymam instancje od DAO, a nie tylko od identyfikatorów.

b) Dodaj @Cacheable do wszystkich metod, duplikuj pamięć podręczną i wykorzystuj więcej pamięci niż potrzeba (załóżmy, że jest wielu wydawców i są to ciężkie obiekty).

Jaka jest najlepsza praktyka związana z tym musi być dość powszechny problem z? Dzięki za wszelkie spostrzeżenia.

+0

Lepiej umieścić dwa pytania w dwóch pytaniach SO. – Raedwald

+0

Dlaczego nie buforować wyniku metody 'findVisiblePublishers'? Tak, po uruchomieniu po raz pierwszy uruchomi dwa zapytania DB, ale to wszystko. Myślę, że to dobry cel do buforowania – Mikhail

+0

Dzięki Michaił. Ponieważ spowoduje buforowanie obiektów wydawcy dla każdej listy wydawców, które zwrócę (i pamięć podręczną). Przedstawione powyżej podejście za pomocą getPublisher (id) nie działa. Kiedy wywołujesz getPublisher (id) z tej samej klasy, pamięć podręczna nie jest pytana, ale żądanie DB jest wykonywane za każdym razem. Oznacza to, że mam dwie instancje tego samego wydawcy w pamięci podręcznej, raz na liście i raz jako pojedynczy element. Kiedy będę miał bardziej podobne metody, sprawy się pogorszą. – marc82ch

Odpowiedz

0

Typowy wzór jest następujący: W przypadku warstwy trwałości używana jest pamięć podręczna drugiego poziomu w trybie hibernacji. W warstwie usługi używaj @Cacheable do buforowania rzeczy, takich jak długie obliczenia lub wyniki połączenia z usługą sieci Web.

+0

Cześć Anton, dziękuję za odpowiedź. Odpowiada to części mojego pierwszego pytania.Robię to dobrze, robiąc to w warstwie DAO, gdy moim celem jest zapisywanie żądań DB (nie mogę używać Hibernate/JPA). W każdym razie, nawet w warstwie serwisowej, mam taki sam problem z pytaniem 2. Przeniesienie @Cacheable na poziom usługi nie rozwiązuje mojego problemu z duplikowaniem pamięci podręcznej. – marc82ch

Powiązane problemy