Estrategias de concurrencia
Después de habilitar el almacenamiento en caché de segundo nivel en Hibernate, debe explicarle a Hibernate qué objetos de Entidad queremos almacenar en caché y cómo.
Para hacer esto, Hibernate tiene una anotación especial para las clases de Entidad: @Cache . Ejemplo:
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
Esta anotación debe escribirse para cada entidad de Entidad para la que queremos usar el caché de segundo nivel. Ejemplo:
@Entity
@Table(name = "employee")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Employee {
@Id
private Integer id;
private Set<Task> tasks;
}
Hibernate tiene 4 posibles estrategias de acceso para una entidad en caché si se accede desde diferentes subprocesos:
- solo lectura
- leer escribir
- lectura-escritura no estricta
- transaccional
Solo lectura . Una estrategia de concurrencia adecuada a los datos que nunca cambia. Hibernate simplemente almacenará estos objetos en su memoria. Úselo solo para datos de referencia.
Las bases de datos almacenan mucha información que nunca cambia. Por ejemplo, una tabla mantiene una lista de eventos que solo se agregan pero nunca se modifican ni eliminan. Si necesita trabajar con esta tabla a través de Hibernate, entonces la estrategia de almacenamiento en caché de solo lectura le conviene.
Leer-escribir (leer-escribir). Utilice esta estrategia para datos que sean principalmente legibles. Sin embargo, Hibernate rastreará los intentos de cambiar estos datos, aunque espera que sean muy poco frecuentes.
Debe almacenar en caché principalmente aquellos objetos que rara vez cambian y que a menudo se leen/solicitan. Si tiene tales objetos, entonces necesita usar la estrategia de lectura y escritura para ellos.
Lectura-escritura no estricta . Esta estrategia no garantiza la coherencia entre la memoria caché y la base de datos. Utilice esta estrategia si los datos casi nunca cambian y una pequeña posibilidad de datos obsoletos no es un problema crítico.
A diferencia de la estrategia de lectura y escritura, esta estrategia asume que los datos mutables no están bloqueados para lectura. Esto puede resultar en que el objeto se cambie en un lugar, mientras que en otro, alguien está leyendo la versión anterior.
Por ejemplo, un usuario ha cambiado su comentario, pero otros usuarios aún ven su versión anterior durante algún tiempo. Si esto no es un problema para usted, utilice la estrategia de lectura y escritura no estricta.
Transaccional . Utilice esta estrategia principalmente para datos de solo lectura donde es importante evitar datos obsoletos en transacciones simultáneas en la rara ocasión de una actualización.
Almacenamiento de datos en un caché
Otro detalle importante sobre el caché de segundo nivel que debe recordar es que Hibernate no almacena los objetos de sus clases en sí. Almacena información como matrices de cadenas, números, etc.
Y el identificador de objeto actúa como un puntero a esta información. Conceptualmente, esto es algo así como un mapa, en el que la identificación del objeto es la clave y las matrices de datos son el valor. Puedes imaginarlo así:
1 -> { "Ivanov", 1, null , {1,2,5} }
2 -> { "Petrov", 2, null , {1,2,5} }
3 -> { "Sidorov", 3, null , {1,2,5} }
Lo cual es muy razonable teniendo en cuenta la cantidad de memoria adicional que ocupa cada objeto.
Además de lo anterior, debe recordar que las dependencias de su clase Entity tampoco se almacenan en caché de forma predeterminada. Por ejemplo, si consideramos la clase anterior, Empleado , entonces, al buscar, la colección de tareas se recuperará de la base de datos , y no del caché de segundo nivel .
Si también desea almacenar en caché las dependencias, la clase debería verse así:
@Entity
@Table(name = "employee")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Employee {
@Id
private Integer id;
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Task> tasks;
}
Y el último detalle: la lectura del caché de segundo nivel ocurre solo si el objeto deseado no se encontró en el caché de primer nivel.
CacheMode
Hibernate permite una gestión de almacenamiento en caché muy flexible. Puede configurar el modo de caché para cada sesión individual o incluso para cada solicitud de base de datos.
Hay cinco modos de este tipo:
- CONSEGUIR
- IGNORAR
- NORMAL
- PONER
- ACTUALIZAR
La siguiente tabla describe su trabajo:
CacheMode | Descripción |
---|---|
CONSEGUIR | Los datos se leen de la memoria caché, pero no se agregan a ella. |
IGNORAR | La sesión no interactúa con el caché. |
NORMAL | Los datos se leen de la memoria caché y se agregan a ella. |
PONER | Los datos nunca se toman del caché, sino que se agregan a él. |
ACTUALIZAR | Los datos nunca se toman del caché, sino que se agregan a él. En este modo, se usa adicionalmente la configuración hibernate.cache.use_minimal_puts. |
Un ejemplo de configuración del modo de caché para una sesión:
session.setCacheMode(CacheMode.GET);
Employee director = session.createQuery("from Employee where id = 4").uniqueResult();
Y también un ejemplo de configuración del modo para la sesión y la solicitud:
session.setCacheMode(CacheMode.GET);
Query query = session.createQuery("from Employee where id = 4");
query.setCacheMode(CacheMode.IGNORE); // Ignore cache work for this request
Employee director = query.uniqueResult();