Ho un requisito per il caricamento di dati statici da un database da utilizzare in un'applicazione Java. Qualsiasi meccanismo di cache dovrebbe avere le seguenti funzionalità:Valori di precarica per una Guava Cache
- Carica tutte dati statici dal database (una volta caricato, questi dati non cambieranno)
- Carica nuovi dati dal database (dati presenti nel database al start non cambia, ma è possibile aggiungere nuovi dati)
Il caricamento lento di tutti i dati non è un'opzione in quanto l'applicazione verrà distribuita in più posizioni geografiche e dovrà comunicare con un singolo database. Il caricamento lento dei dati renderà la prima richiesta per un elemento specifico troppo lento dove l'applicazione si trova in una regione diversa rispetto al database.
Ho utilizzato l'API MapMaker in Guava con esito positivo, ma ora stiamo eseguendo l'aggiornamento all'ultima versione e non riesco a trovare la stessa funzionalità nell'API CacheBuilder; Non riesco a trovare un modo pulito per caricare tutti i dati all'avvio.
Un modo sarebbe caricare tutte le chiavi dal database e caricarle singolarmente attraverso la cache. Ciò funzionerebbe ma risulterebbe in chiamate N + 1 al database, che non è proprio la soluzione efficiente che sto cercando.
public void loadData(){
List<String> keys = getAllKeys();
for(String s : keys)
cache.get(s);
}
o l'altra soluzione è quella di utilizzare un'implementazione ConcurrentHashMap e gestire tutti i thread e le voci mancanti me stesso? Non sono entusiasta di farlo poiché le API di MapMaker e CacheBuilder forniscono gratuitamente il blocco del thread basato sulla chiave senza dover fornire test aggiuntivi. Sono anche abbastanza sicuro che le implementazioni di MapMaker/CacheBuilder avranno alcune efficienze che non conosco/non ho il tempo di investigare.
public Element get(String key){
Lock lock = getObjectLock(key);
lock.lock();
try{
Element ret = map.get(key)
if(ret == null){
ret = getElement(key); // database call
map.put(key, e);
}
return ret;
}finally {
lock.unlock();
}
}
Qualcuno può pensare a una soluzione migliore alle mie due esigenze?
Feature Request
Non credo di pre-caricamento di una cache è un requisito raro, quindi sarebbe bello se il CacheBuilder fornito un'opzione di configurazione per precaricare la cache . Penso fornendo un'interfaccia (molto simile CacheLoader) che popolano la cache allo start-up sarebbe una soluzione ideale, come ad esempio:
CacheBuilder.newBuilder().populate(new CachePopulator<String, Element>(){
@Override
public Map<String, Element> populate() throws Exception {
return getAllElements();
}
}).build(new CacheLoader<String, Element>(){
@Override
public Element load(String key) throws Exception {
return getElement(key);
}
});
Questa implementazione consentirebbe la cache per essere pre-popolato con tutti gli elementi rilevanti oggetti, mantenendo la sottostante CustomConcurrentHashMap non visibile al mondo esterno.
Aggiungere la richiesta di funzionalità all'elenco dei problemi di Guava. –
Aggiunto (numero 775) – Richard
http://code.google.com/p/guava-libraries/issues/detail?id=775 –