Skriv aldrig din cachningslösning

Ett annat sätt att påskynda arbetet med databasen är att cache-minne objekt som vi redan efterfrågat tidigare.

Viktig! Skriv aldrig din egen cachelösning. Den här uppgiften har så många fallgropar som du aldrig drömt om.

Utgåva 1 - cache-spolning . Ibland inträffar händelser när ett objekt behöver tas bort från cachen eller uppdateras i cachen. Det enda sättet att göra detta på ett kompetent sätt är att skicka alla förfrågningar till databasen genom cachemotorn. Annars måste du varje gång uttryckligen tala om för cachen vilka objekt i den som ska raderas eller uppdateras.

Problem 2 - brist på minne . Cachning verkar vara en bra idé tills du upptäcker att objekt i minnet tar upp mycket utrymme. Du behöver ytterligare tiotals gigabyte minne för att serverapplikationens cache ska fungera effektivt.

Och eftersom det alltid är brist på minne behövs en effektiv strategi för att ta bort objekt från cachen. Detta påminner något om sophämtaren i Java. Och som ni minns har de bästa hjärnorna i årtionden uppfunnit olika sätt att markera föremål i generationer, etc.

Problem 3 - olika strategier . Som praxis visar är olika strategier för lagring och uppdatering i cachen effektiva för olika objekt. Ett effektivt cachningssystem kan inte göra bara en strategi för alla objekt.

Problem 4 - Effektiv lagring av . Du kan inte bara lagra objekt i cachen. Objekt innehåller alltför ofta referenser till andra objekt osv. I den här takten behöver du ingen sophämtare: den har bara inget att ta bort.

Därför, istället för att lagra objekten själva, är det ibland mycket mer effektivt att lagra värdena för deras primitiva fält. Och system för att snabbt konstruera objekt baserat på dem.

Som ett resultat kommer du att få ett helt virtuellt DBMS i minnet, som bör fungera snabbt och förbruka lite minne.

Databascaching

Förutom att cache direkt i ett Java-program organiseras cachning ofta direkt i databasen.

Det finns fyra stora tillvägagångssätt:

Det första tillvägagångssättet är att denormalisera databasen . SQL-servern lagrar data i minnet annorlunda än hur de lagras i tabeller.

När data lagras på disk i tabeller försöker utvecklare väldigt ofta undvika dataduplicering så mycket som möjligt - denna process kallas databasnormalisering. Så för att påskynda arbetet med data i minnet utförs den omvända processen - databasdenormalisering. Ett gäng relaterade tabeller kan redan lagras i en kombinerad form - i form av enorma tabeller, etc.

Den andra metoden är query caching . Och sökresultat.

DBMS ser att det väldigt ofta kommer samma eller liknande förfrågningar till den. Sedan börjar den helt enkelt cachelagra dessa förfrågningar och deras svar. Men samtidigt måste du se till att rader som har ändrats i databasen tas bort från cachen i tid.

Detta tillvägagångssätt kan vara mycket effektivt med en människa som kan analysera frågor och hjälpa DBMS att ta reda på hur man bäst cachelagrar dem.

Den tredje metoden är en databas i minnet .

Ett annat vanligt använt tillvägagångssätt. En annan databas placeras mellan servern och DBMS, som lagrar all data endast i minnet. Det kallas även In-Memory-DB. Om du har många olika servrar som har åtkomst till samma databas, kan du med In-Memory-DB organisera cachelagring baserat på typen av en viss server.

Exempel:

Approach 4- databaskluster . Flera skrivskyddade baser.

En annan lösning är att använda ett kluster: flera DBMS av samma typ innehåller identiska data. Samtidigt kan du läsa data från alla databaser, och bara skriva till en. Som sedan synkroniseras med resten av databaserna.

Detta är en mycket bra lösning eftersom den är lätt att konfigurera och fungerar i praktiken. Vanligtvis, för en begäran till databasen att ändra data, kommer 10-100 förfrågningar om att läsa data till den.

Typer av cachning i Hibernate

Hibernate stöder tre nivåer av cachelagring:

  • Cachning på sessionsnivå (session)
  • Cachning på SessionFactory-nivå
  • Cacheförfrågningar (och deras resultat)

Du kan försöka representera detta system i form av en sådan figur:

Den enklaste typen av cachelagring (även kallad den första nivåns cache ) implementeras på Hibernate-sessionsnivån. Hibernate använder alltid denna cache som standard och kan inte inaktiveras .

Låt oss omedelbart överväga följande exempel:

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

assertTrue(director1 == director2);

Det kan tyckas att två frågor till databasen kommer att köras här, men så är inte fallet. Efter den första begäran till databasen cachelagras Employee-objektet. Och om du frågar objektet igen i samma session kommer Hibernate att returnera samma Java-objekt.

Samma objekt innebär att även objektreferenser kommer att vara identiska. Det är egentligen samma objekt.

Metoderna save() , update() , saveOrUpdate() , load() , get() , list() , iterate() och scroll() kommer alltid att använda cacheminnet på första nivån. Egentligen finns det inget mer att tillägga.

Caching på andra nivån

Om den första nivåns cache är bunden till sessionsobjektet, då är den andra nivåns cache bunden till sessionsobjektet.SessionFactory. Vilket innebär att synligheten för objekt i denna cache är mycket bredare än i den första nivåns cache.

Exempel:

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

I det här exemplet kommer två frågor att göras till databasen. Hibernate kommer att returnera identiska objekt, men det kommer inte att vara samma objekt - de kommer att ha olika referenser.

Caching på andra nivån är inaktiverat som standard . Därför har vi två frågor till databasen istället för en.

För att aktivera det måste du skriva följande rader i filen hibernate.cfg.xml:

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

Efter att ha aktiverat cachelagring på andra nivån kommer Hibernate-beteendet att ändras lite:

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

Först efter alla dessa manipulationer kommer den andra nivåns cache att aktiveras, och i exemplet ovan kommer endast en fråga till databasen att exekveras.