Strategii de concurență

După ce activați stocarea în cache de nivel al doilea în Hibernate, trebuie să îi explicați lui Hibernate ce obiecte Entity dorim să le memorăm în cache și cum.

Pentru a face acest lucru, Hibernate are o adnotare specială pentru clasele Entity - @Cache . Exemplu:

@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)

Această adnotare trebuie scrisă pentru fiecare entitate de entitate pentru care dorim să folosim cache-ul de al doilea nivel. Exemplu:

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

Hibernate are 4 strategii de acces posibile pentru o entitate memorată în cache dacă este accesată din fire diferite:

  • numai pentru citire
  • Citeste, scrie
  • nonstrict-citire-scriere
  • tranzacționale

Numai citire . O strategie de concurență adecvată datelor, care nu se schimbă niciodată. Hibernate va stoca pur și simplu aceste obiecte în memoria sa. Utilizați-l doar pentru date de referință.

Bazele de date stochează o mulțime de informații care nu se schimbă niciodată. De exemplu, un tabel păstrează o listă de evenimente care sunt doar adăugate, dar niciodată modificate sau eliminate. Dacă trebuie să lucrați cu acest tabel prin Hibernate, atunci strategia de stocare în cache numai pentru citire vi se va potrivi.

Citire-scriere (citire-scriere). Utilizați această strategie pentru date care sunt în principal lizibile. Cu toate acestea, Hibernate va urmări încercările de a schimba aceste date, deși se așteaptă ca acestea să fie foarte rare.

Trebuie să puneți în cache în principal acele obiecte care se schimbă rar și sunt adesea citite/solicitate. Dacă aveți astfel de obiecte, atunci trebuie să utilizați strategia de citire-scriere pentru ele.

Nestrict-citire-scriere . Această strategie nu garantează consistența între cache și baza de date. Utilizați această strategie dacă datele nu se schimbă aproape niciodată și o șansă mică de date învechite nu este o problemă critică.

Spre deosebire de strategia de citire-scriere, această strategie presupune că datele mutabile nu sunt blocate pentru citire. Acest lucru poate duce la schimbarea obiectului într-un loc, în timp ce în altul, cineva citește versiunea veche a acestuia.

De exemplu, un utilizator și-a schimbat comentariul, dar alți utilizatori încă văd versiunea sa veche de ceva timp. Dacă aceasta nu este o problemă pentru dvs., atunci utilizați strategia nonstrict-read-write.

Tranzacțional . Utilizați această strategie pentru date în principal numai pentru citire, unde este important să preveniți datele învechite în tranzacțiile concurente, cu ocazia rară a unei actualizări.

Stocarea datelor într-un cache

Un alt detaliu important despre cache-ul de al doilea nivel pe care ar trebui să-l amintiți este că Hibernate nu stochează obiectele claselor dvs. în sine. Stochează informații ca șiruri de caractere, numere etc.

Iar identificatorul de obiect acționează ca un pointer către această informație. Conceptual, aceasta este ceva ca o hartă, în care id-ul obiectului este cheia, iar matricele de date sunt valoarea. Vă puteți imagina așa:

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

Ceea ce este foarte rezonabil, având în vedere câtă memorie suplimentară ocupă fiecare obiect.

În plus față de cele de mai sus, ar trebui să vă amintiți că dependențele clasei dvs. Entity nu sunt, de asemenea, memorate în cache în mod implicit. De exemplu, dacă luăm în considerare clasa de mai sus, Employee , atunci la preluare, colecția de sarcini va fi preluată din baza de date și nu din memoria cache de nivel al doilea .

Dacă doriți să memorați și dependențele în cache, atunci clasa ar trebui să arate astfel:

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

Și ultimul detaliu - citirea din memoria cache de nivel al doilea are loc numai dacă obiectul dorit nu a fost găsit în memoria cache de nivel întâi.

CacheMode

Hibernare permite o gestionare foarte flexibilă a stocării în cache. Puteți seta modul cache pentru fiecare sesiune individuală sau chiar pentru fiecare cerere de bază de date.

Există cinci astfel de moduri:

  • OBȚINE
  • IGNORA
  • NORMAL
  • A PUNE
  • REÎMPROSPĂTA

Tabelul de mai jos descrie activitatea lor:

CacheMode Descriere
OBȚINE Datele sunt citite din cache, dar nu sunt adăugate la acesta.
IGNORA Sesiunea nu interacționează cu memoria cache.
NORMAL Datele sunt citite din cache și adăugate la acesta.
A PUNE Datele nu sunt niciodată luate din cache, ci adăugate la acesta.
REÎMPROSPĂTA Datele nu sunt niciodată luate din cache, ci adăugate la acesta. În acest mod, se utilizează suplimentar setarea hibernate.cache.use_minimal_puts.

Un exemplu de setare a modului cache pentru o sesiune:

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

Și, de asemenea, un exemplu de setare a modului pentru sesiune și cerere:

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