Schrijf nooit uw caching-oplossing

Een andere manier om het werk met de database te versnellen, is door objecten in de cache op te slaan die we al eerder hebben opgevraagd.

Belangrijk! Schrijf nooit uw eigen caching-oplossing. Deze taak heeft zoveel valkuilen waar je nooit van hebt gedroomd.

Probleem 1 - cache leegmaken . Soms vinden gebeurtenissen plaats wanneer een object uit de cache moet worden verwijderd of in de cache moet worden bijgewerkt. De enige manier om dit vakkundig te doen, is door alle verzoeken door te geven aan de database via de cache-engine. Anders moet u de cache elke keer expliciet vertellen welke objecten erin moeten worden verwijderd of bijgewerkt.

Probleem 2 - gebrek aan geheugen . Caching lijkt een geweldig idee totdat je merkt dat objecten in het geheugen veel ruimte innemen. U hebt extra tientallen gigabytes aan geheugen nodig om de cache van de servertoepassing effectief te laten werken.

En aangezien er altijd een tekort aan geheugen is, is een effectieve strategie nodig om objecten uit de cache te verwijderen. Dit lijkt enigszins op de vuilnisman op Java. En zoals u zich herinnert, hebben de knapste koppen al tientallen jaren verschillende manieren bedacht om objecten te markeren op basis van generaties, enz.

Probleem 3 - verschillende strategieën . Zoals de praktijk laat zien, zijn verschillende strategieën voor het opslaan en bijwerken in de cache effectief voor verschillende objecten. Een efficiënt cachesysteem kan niet slechts één strategie voor alle objecten uitvoeren.

Probleem 4 - Efficiënte opslag van . U kunt niet zomaar objecten in de cache opslaan. Objecten bevatten te vaak verwijzingen naar andere objecten, enz. In dit tempo heb je geen vuilnisman nodig: hij heeft gewoon niets om te verwijderen.

Daarom is het soms veel efficiënter om de waarden van hun primitieve velden op te slaan in plaats van de objecten zelf op te slaan. En systemen om op basis daarvan snel objecten te construeren.

Als gevolg hiervan krijgt u een volledig virtueel DBMS in het geheugen, dat snel zou moeten werken en weinig geheugen zou verbruiken.

Databasecaching

Naast caching direct in een Java-programma wordt caching vaak direct in de database georganiseerd.

Er zijn vier grote benaderingen:

De eerste benadering is het denormaliseren van de database . De SQL-server slaat gegevens op een andere manier op in het geheugen dan hoe ze in tabellen worden opgeslagen.

Wanneer gegevens op schijf worden opgeslagen in tabellen, proberen ontwikkelaars heel vaak gegevensduplicatie zoveel mogelijk te vermijden - dit proces wordt databasenormalisatie genoemd. Dus om het werk met gegevens in het geheugen te versnellen, wordt het omgekeerde proces uitgevoerd: denormalisatie van de database. Een aantal gerelateerde tabellen kan al in een gecombineerde vorm worden opgeslagen - in de vorm van enorme tabellen, enz.

De tweede benadering is query caching . En queryresultaten.

Het DBMS ziet dat er heel vaak dezelfde of soortgelijke verzoeken bij hem binnen komen. Daarna begint het gewoon met het cachen van deze verzoeken en hun antwoorden. Maar tegelijkertijd moet u ervoor zorgen dat rijen die in de database zijn gewijzigd, tijdig uit de cache worden verwijderd.

Deze aanpak kan zeer effectief zijn bij een mens die query's kan analyseren en het DBMS kan helpen uitzoeken hoe ze het beste in de cache kunnen worden opgeslagen.

De derde benadering is een in-memory database .

Een andere veelgebruikte aanpak. Een andere database wordt tussen de server en het DBMS geplaatst, die alle gegevens alleen in het geheugen opslaat. Het wordt ook wel In-Memory-DB genoemd. Als u veel verschillende servers hebt die toegang hebben tot dezelfde database, kunt u met behulp van In-Memory-DB caching organiseren op basis van het type van een bepaalde server.

Voorbeeld:

Aanpak 4 - databasecluster . Verschillende alleen-lezen bases.

Een andere oplossing is het gebruik van een cluster: meerdere DBMS'en van hetzelfde type bevatten identieke gegevens. Tegelijkertijd kunt u gegevens uit alle databases lezen en naar slechts één database schrijven. Die vervolgens wordt gesynchroniseerd met de rest van de databases.

Dit is een zeer goede oplossing omdat het eenvoudig te configureren is en in de praktijk werkt. Gewoonlijk komen er voor één verzoek aan de database om gegevens te wijzigen 10-100 verzoeken om gegevens te lezen binnen.

Soorten caching in Hibernate

Hibernate ondersteunt drie niveaus van caching:

  • Caching op sessieniveau (sessie)
  • Caching op SessionFactory-niveau
  • Caching-aanvragen (en hun resultaten)

Je kunt proberen dit systeem weer te geven in de vorm van zo'n figuur:

Het eenvoudigste type caching (ook wel cache van het eerste niveau genoemd ) wordt geïmplementeerd op het Hibernate-sessieniveau. Hibernate gebruikt standaard altijd deze cache en kan niet worden uitgeschakeld .

Laten we meteen het volgende voorbeeld bekijken:

Employee director1 = session.get(Employee.class, 4);
Employee director2 = session.get(Employee.class, 4);

assertTrue(director1 == director2);

Het lijkt misschien dat hier twee query's naar de database worden uitgevoerd, maar dat is niet zo. Na het eerste verzoek aan de database wordt het object Employee in de cache geplaatst. En als u het object in dezelfde sessie opnieuw opvraagt, retourneert Hibernate hetzelfde Java-object.

Hetzelfde object betekent dat zelfs objectreferenties identiek zijn. Het is echt hetzelfde voorwerp.

De methoden save() , update() , saveOrUpdate() , load() , get() , list() , iterate() en scroll() gebruiken altijd de cache van het eerste niveau. Eigenlijk valt er niets meer aan toe te voegen.

Caching op het tweede niveau

Als de cache op het eerste niveau is gebonden aan het sessieobject, is de cache op het tweede niveau gebonden aan het sessieobject.SessionFactory. Wat betekent dat de zichtbaarheid van objecten in deze cache veel breder is dan in de cache op het eerste niveau.

Voorbeeld:

Session session = factory.openSession();
Employee director1 = session.get(Employee.class, 4);
session.close();

Session session = factory.openSession();
Employee director2 = session.get(Employee.class, 4);
session.close();

assertTrue(director1 != director2);
assertTrue(director1.equals(director2));

In dit voorbeeld worden twee query's naar de database uitgevoerd. Hibernate zal identieke objecten retourneren, maar het zal niet hetzelfde object zijn - ze zullen verschillende referenties hebben.

Caching op het tweede niveau is standaard uitgeschakeld . Daarom hebben we twee queries naar de database in plaats van één.

Om het in te schakelen, moet u de volgende regels in het bestand hibernate.cfg.xml schrijven:

<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletEhCacheProvider"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>

Na het inschakelen van caching op het tweede niveau, zal het slaapstandgedrag een beetje veranderen:

Session session = factory.openSession();
Employee director1 = session.get(Employee.class, 4);
session.close();

Session session = factory.openSession();
Employee director2 = session.get(Employee.class, 4);
session.close();

assertTrue(director1 == director2);

Pas na al deze manipulaties wordt de cache op het tweede niveau ingeschakeld en in het bovenstaande voorbeeld wordt slechts één query naar de database uitgevoerd.