Tengo un requisito en el que estamos cargando datos estáticos de una base de datos para su uso en una aplicación Java. Cualquier mecanismo de caché debe tener la funcionalidad siguiente:Valores de precarga para un caché de Guava
- carga todos los datos estáticos de la base de datos (una vez cargado, estos datos no cambiarán)
- de carga nuevos datos de la base de datos (datos presentes en la base de datos en Inicio- hasta no va a cambiar, pero es posible añadir nuevos datos)
Lazy carga de todos los datos no es una opción ya que la aplicación se va a distribuir a múltiples ubicaciones geográficas y tendrá que comunicarse con una base de datos única. La carga lenta de los datos hará que la primera solicitud de un elemento específico sea demasiado lenta cuando la aplicación se encuentre en una región diferente de la base de datos.
He estado utilizando la API de MapMaker en Guava con éxito, pero ahora nos estamos actualizando a la última versión y parece que no puedo encontrar la misma funcionalidad en la API de CacheBuilder; Parece que no puedo encontrar una forma clara de cargar todos los datos en la puesta en marcha.
Una forma sería cargar todas las claves de la base de datos y cargarlas a través del caché individualmente. Esto funcionaría pero daría como resultado llamadas N + 1 a la base de datos, que no es la solución más eficiente que estoy buscando.
public void loadData(){
List<String> keys = getAllKeys();
for(String s : keys)
cache.get(s);
}
O la otra solución es utilizar una aplicación ConcurrentHashMap y manejar todos los hilos y las entradas que faltan a mí mismo? No estoy interesado en hacer esto ya que las API de MapMaker y CacheBuilder proporcionan el bloqueo de hilos basado en claves de forma gratuita sin tener que proporcionar pruebas adicionales. También estoy bastante seguro de que las implementaciones de MapMaker/CacheBuilder tendrán algunas eficiencias que desconozco/no tengo tiempo para investigar.
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();
}
}
¿Alguien puede pensar en una mejor solución para mis dos requisitos?
Pedido de funciones
No creo pre-carga de una memoria caché es un requisito poco común, por lo que sería bueno si el CacheBuilder proporciona una opción de configuración para cargar previamente la memoria caché . Creo que proporciona una interfaz (al igual que CacheLoader) que poblar la memoria caché en el arranque sería una solución ideal, tales como:
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);
}
});
Esta aplicación permitiría que el caché de ser pre-rellena con todo elemento relevante objetos, manteniendo el CustomConcurrentHashMap subyacente no visible para el mundo exterior.
Agregue la solicitud de función a la lista de problemas de Guava. –
Agregado (problema 775) – Richard
http://code.google.com/p/guava-libraries/issues/detail?id=775 –