2011-09-15 16 views
9

Actualmente estoy desarrollando mi propio pequeño ORM, y me encuentro ante la tarea de crear un mapeo de canonización para evitar cargar la misma entidad de la base de datos más de una vez.¿Cómo implementar una asignación de canonicalización en Java?

Mi enfoque actual es utilizar un HashMap<Object, WeakReference<Object>>. La clave es la clave principal de la entidad de base de datos asignada (un ArrayList<Object> si es una clave compuesta), y los valores son WeakReference<Object>.

Mi problema principal es cómo limpiar el mapa? Cuando un objeto no se usa más, la referencia débil en el mapa irá al null, y solo lo descubriré en la siguiente búsqueda (o nunca, si no vuelvo a mirar el objeto). Podría hacer que las referencias débiles se registren con un ReferenceQueue cuando se borren, y luego verificar esa cola cada vez que busco algo. Sin embargo, la referencia borrada no me dio ninguna pista sobre qué objeto se borró, así que supongo que tendré que crear la subclase WeakReference para almacenar la clave en el mapa, por lo que puedo eliminarla una vez que se borre la referencia.

¿Es este el camino a seguir, o hay alguna forma más sencilla de implementar esto?

Respuesta

13

Recomendaría usar Guava MapMaker, o CacheBuilder en r10.

Permiten el desalojo automático basado en el tiempo y el tamaño *, así como también admiten claves débiles o valores. (Las próximas CacheBuilder promete ser especialmente adaptados a este tipo de caso de uso.)

Así puede inicializar su mapa:

ConcurrentMap<Key, Object> cache = new MapMaker() 
     .weakValues() 
     .makeMap(); 

Y el beneficio inmediato será que cuando un valor es basura recogida, el toda la entrada será eliminada. Además, se puede usar un mapa de computación:

ConcurrentMap<Key, Object> cache = new MapMaker() 
     .weakValues() 
     .makeComputingMap(loadFunction); 

donde loadFunction es una Function<Key, Object> que carga un objeto de la base de datos. La ventaja de esto es que el mapa manejará solicitudes concurrentes para un objeto en particular, asegurando que la consulta solo se llame una vez. Además, el código de solicitud solo necesita llamar al get() y siempre puede esperar que el objeto vuelva, ya sea desde el caché o la base de datos.

Estos ejemplos están usando MapMaker - No he tenido el placer de jugar con CacheBuilder todavía.

Consulte esta pregunta my ideal cache using guava para ver más ejemplos. Esa publicación analiza cómo combinar el desalojo basado en el tiempo con la canonicalización.

+2

Al principio dudé en añadir esta biblioteca, pero ahora que lo hice, me pregunto por qué no lo hice antes. ¡Gracias por esta gran respuesta! –

Cuestiones relacionadas