Стратегии за едновременност

След като активирате кеширането от второ ниво в Hibernate, трябва да обясните на Hibernate кои обекти Entity искаме да кешираме и How.

За да направи това, Hibernate има специална анотация за Entity класове - @Cache . Пример:

@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)

Тази анотация трябва да бъде написана за всеки обект Entity, за който искаме да използваме кеша от второ ниво. Пример:

@Entity
@Table(name = "employee")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Employee {
    @Id
    private Integer id;
    private Set<Task> tasks;
}

Hibernate има 4 възможни стратегии за достъп до кеширан обект, ако се осъществява достъп от различни нишки:

  • Само за четене
  • чети пиши
  • нестриктно четене-запис
  • транзакционен

Само за четене . Стратегия за паралелност, подходяща за данни, която никога не се променя. Hibernate просто ще съхрани тези обекти в паметта си. Използвайте го само за справочни данни.

Базите данни съхраняват много информация, която никога не се променя. Например една table съхранява списък със събития, които само се добавят, но никога не се променят or премахват. Ако трябва да работите с тази table през Hibernate, тогава стратегията за кеширане само за четене ще ви подхожда.

Четене-запис (четене-запис). Използвайте тази стратегия за данни, които са основно четими. Hibernate обаче ще проследи опитите за промяна на тези данни, въпреки че очаква те да са много редки.

Трябва да кеширате главно онези обекти, които рядко се променят и често се четат/изискват. Ако имате такива обекти, тогава трябва да използвате стратегията за четене и запис за тях.

Нестриктно четене-запис . Тази стратегия не гарантира съгласуваност между кеша и базата данни. Използвайте тази стратегия, ако данните почти никога не се променят и малък шанс за остарели данни не е критичен проблем.

За разлика от стратегията за четене-запис, тази стратегия предполага, че променливите данни не са заключени за четене. Това може да доведе до промяна на обекта на едно място, докато на друго някой чете старата му version.

Например потребител е променил своя коментар, но други потребители все още виждат старата му version за известно време. Ако това не е проблем за вас, тогава използвайте стратегията за нестриктно четене-запис.

Транзакционен . Използвайте тази стратегия предимно за данни само за четене, когато е важно да предотвратите остарели данни в едновременни транзакции в редките случаи на актуализация.

Съхраняване на данни в кеш памет

Друга важна подробност за кеша от второ ниво, която трябва да запомните е, че Hibernate не съхранява самите обекти на вашите класове. Той съхранява информация като масиви от низове, числа и др.

И идентификаторът на обекта действа като указател към тази информация. Концептуално това е нещо като карта, в която id на обекта е ключът, а масивите с данни са стойността. Можете да си го представите така:

1 -> { "Ivanov", 1, null , {1,2,5} }
2 -> { "Petrov", 2, null , {1,2,5} }
3 -> { "Sidorov", 3, null , {1,2,5} }

Което е много разумно, като се има предвид колко допълнителна памет заема всеки обект.

В допълнение към горното, трябва да запомните, че зависимостите на вашия клас Entity също не се кешират по подразбиране. Например, ако разгледаме класа по-горе, Employee , тогава при извличане колекцията от задачи ще бъде извлечена от базата данни , а не от кеша от второ ниво .

Ако искате да кеширате и зависимости, тогава класът трябва да изглежда така:

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

И последният детайл - четенето от кеша от второ ниво се извършва само ако желаният обект не е намерен в кеша от първо ниво.

CacheMode

Hibernate позволява много гъвкаво управление на кеширането. Можете да зададете режима на кеша за всяка отделна сесия or дори за всяка заявка за база данни.

Има пет такива режима:

  • ВЗЕМЕТЕ
  • ИГНОРИРАЙТЕ
  • НОРМАЛНО
  • СЛАГАМ
  • ОБНОВЯВАНЕ

Таблицата по-долу описва тяхната работа:

CacheMode Описание
ВЗЕМЕТЕ Данните се четат от кеша, но не се добавят към него.
ИГНОРИРАЙТЕ Сесията не взаимодейства с кеша.
НОРМАЛНО Данните се четат от кеша и се добавят към него.
СЛАГАМ Данните никога не се вземат от кеша, а се добавят към него.
ОБНОВЯВАНЕ Данните никога не се вземат от кеша, а се добавят към него. В този режим допълнително се използва настройката hibernate.cache.use_minimal_puts.

Пример за настройка на кеш режима за сесия:

session.setCacheMode(CacheMode.GET);
Employee director = session.createQuery("from Employee where id = 4").uniqueResult();

А също и пример за настройка на режима за сесията и заявката:

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();