2013-06-11 5 views
5

Sono nuovo per la primavera e sono molto entusiasta di tutto ciò che offre!Best practice per DAO del mondo reale utilizzando le annotazioni annotabili @

In questo momento, sto cercando di modernizzare un paio di DAO nel mio progetto esistente. In particolare, voglio sostituire il mio vecchio codice JDBC con il supporto Spring Jdbc e introdurre la cache trasparente di Spring.

  1. Prima domanda: ho ragione che lo strato DAO è il posto giusto per aggiungere annotazioni @Cacheable? O lo fai nel livello aziendale?

  2. Posso seguire tutti i semplici esempi che si trovano in rete. Tuttavia, quando si tratta di più codice mondo reale, mi si blocca:

In particolare, ho diversi metodi che restituiscono le istanze del mio modello Publisher. Nelle implementazioni della cache manuale ho sempre verificato che solo una istanza sia memorizzata nella cache e recuperata per i diversi metodi getPublisher(). Tuttavia, utilizzando @Cacheable e cercando di incapsulare la cache nella DAO, ho il problema, che l'annotazione non funziona per le chiamate dei metodi locali (a causa del proxy).

Ecco il mio codice di esempio:

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

Questa era la mia idea, che, come detto, non funziona.

Le uniche alternative che posso vedere in questo momento sono:

a) memorizzare nella cache il metodo getPublisher(publisherId) Solo e definire tutti gli altri metodi che restituiscono Publisher s per tornare int s (publisherIds), o elenchi della stessa. Questo non sembra naturale dal punto di vista dell'API. Come servizio o logica aziendale, mi aspetterei di ottenere istanze dal DAO, non solo ID.

b) Aggiungere @Cacheable a tutti i metodi, duplicare la cache e utilizzare più memoria del necessario (presupponiamo che ci siano molti editori e che siano oggetti pesanti).

Qual è la migliore pratica in questo deve-be-pretty-common problema? Grazie per eventuali approfondimenti.

+0

Meglio porre due domande in due domande SO. – Raedwald

+0

Perché non memorizzare nella cache il risultato del metodo 'findVisiblePublishers'? Sì, eseguirà due query DB quando viene invocato per la prima volta, ma il gioco è fatto. Penso che sia un buon obiettivo per il caching – Mikhail

+0

Grazie Mikhail. Perché memorizzerà nella cache gli oggetti Publisher per ogni elenco di Publisher che restituisco (e cache). L'approccio mostrato sopra usando getPublisher (id) non funziona. Quando chiami getPublisher (id) dalla stessa classe, la cache non viene richiesta, ma una richiesta DB viene eseguita ogni volta. Ciò significa che sono presenti due istanze dello stesso server di pubblicazione nella cache, una volta nell'elenco e una volta come un singolo elemento. Quando ho metodi più simili, le cose peggioreranno. – marc82ch

risposta

0

Il motivo comune è il seguente: Per il livello di persistenza si utilizza la cache di secondo livello in ibernazione. Per il livello di servizio si utilizza @Cacheable per memorizzare nella cache cose come calcoli lunghi o risultati di chiamate al servizio web.

+0

Ciao Anton, grazie per la tua risposta. Questo risponde a parte della mia prima domanda.Quindi, lo sto facendo bene, quando lo faccio nel livello DAO quando il mio scopo è quello di salvare le richieste DB (non posso usare Hibernate/JPA). Comunque, anche nel livello di servizio, avrei lo stesso problema per la domanda 2. Il passaggio da @Cacheable al livello di servizio non risolve il mio problema con la memorizzazione nella cache duplicata. – marc82ch