3 bežné problémy s výkonom v režime dlhodobého spánku a ako ich nájsť v protokole

1. Úvod

Pravdepodobne ste už čítali niektoré sťažnosti na zlé výkony režimu dlhodobého spánku, alebo ste s nimi sami zápasili. Hibernáciu používam už viac ako 15 rokov a na tieto problémy som narazil viac ako dosť.

V priebehu rokov som sa dozvedel, že týmto problémom sa dá vyhnúť a že ich veľa nájdete v protokole. V tomto príspevku vám chcem ukázať, ako môžete nájsť a opraviť 3 z nich.

2. Vyhľadajte a opravte problémy s výkonom

2.1. Zaznamenávajte výpisy SQL do výroby

Prvý problém s výkonom je mimoriadne ľahko rozpoznateľný a často ignorovaný. Je to protokolovanie príkazov SQL v produkčnom prostredí.

Písanie niektorých výpisov z denníka to neznie veľmi dobre a existuje veľa aplikácií, ktoré robia presne to. Ale je to mimoriadne neefektívne, najmä prostredníctvom System.out.println ako to robí režim dlhodobého spánku, ak nastavíte show_sql parameter vo vašej konfigurácii režimu dlhodobého spánku na pravda:

Hibernácia: vyberte order0_.id ako id1_2_, order0_.orderNumber ako orderNum2_2_, order0_.verziu ako verziu3_2_ z nákupuObjednávka order0_ Hibernácia: vyberte items0_.order_id ako order_id4_0_0_, items0_.id ako id1_0_0_, items0_.id ako id1___id_0_id items0_.product_id ako product_5_0_1_, items0_.množstvo ako množstvo2_0_1_, items0_.verzia ako verzia3_0_1_ z OrderItem items0_ kde items0_.order_id =? Hibernácia: vyberte items0_.order_id ako order_id4_0_0_, items0_.id ako id1_0_0_, items0_.id ako id1_0_1_, items0_.order_id ako order_id4_0_1_, items0_.product_id ako produkt_5_0_1_, položky0_.počet_v_množstve_v_množstve_v_množstve_množstve_v_množstve_množstvo_v_množstve_množstvo_v_množstve_množstvo_v_množstve_množstvo_v_množstve ako_množstvo_0_v_množstve ako množstvo_0_1 order_id =? Hibernácia: vyberte item0_.order_id ako order_id4_0_0_, items0_.id ako id1_0_0_, items0_.id ako id1_0_1_, items0_.order_id ako order_id4_0_1_, items0_.product_id ako produkt_5_0_1_, položky0_.číslo_v_množstve_množstvo_v_množstve_množstvo_v_množstve_množstvo_množstvo_v_množstve_množstvo_množstvo_v_množstve_množstvo_v_množstve_množstvo_v_množstve_množstvo_v_množstve_v_množstve ako_množstvo_0 order_id =?

V jednom z mojich projektov som nastavením nastavil výkon o 20% v priebehu niekoľkých minút show_sql do nepravdivé. To je druh úspechu, ktorý by ste chceli oznámiť na nasledujúcom samostatnom stretnutí 🙂

Je celkom zrejmé, ako môžete vyriešiť tento problém s výkonom. Stačí otvoriť konfiguráciu (napr. Súbor persistence.xml) a nastaviť show_sql parameter do nepravdivé. Tieto informácie vo výrobe aj tak nepotrebujete.

Možno ich však budete potrebovať počas vývoja. Ak to neurobíte, použijete dve rôzne konfigurácie režimu dlhodobého spánku (čo by ste nemali), deaktivovali ste aj tam protokolovanie príkazov SQL. Riešením je použitie 2 rôznych konfigurácií protokolov pre vývoj a výrobu, ktoré sú optimalizované pre špecifické požiadavky runtime prostredia.

Konfigurácia vývoja

Konfigurácia vývoja by mala poskytovať čo najviac užitočných informácií, aby ste videli, ako režim dlhodobého spánku interaguje s databázou. Preto by ste mali aspoň vygenerované príkazy SQL prihlásiť do svojej vývojovej konfigurácie. Môžete to urobiť aktiváciou DEBUG správa pre org.hibernate.SQL kategórie. Ak chcete tiež vidieť hodnoty vašich parametrov väzby, musíte nastaviť úroveň protokolu z org.hibernate.type.descriptor.sql do TRACE:

log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern =% d {HH: mm: ss, SSS}% -5p [% c] -% m% n log4j.rootLogger = info, štandardný výstup # základnej úrovne pre všetky správy log4j.logger.org.hibernate = info # príkazy a parametre SQL log4j.logger.org.hibernate.SQL = ladenie log4j.logger.org.hibernate.type.descriptor.sql = stopa

Nasledujúci úryvok kódu zobrazuje niektoré príklady správ protokolu, ktoré program Hibernate píše s touto konfiguráciou protokolu. Ako vidíte, získate podrobné informácie o vykonanom dotaze SQL a všetkých nastavených a získaných hodnotách parametrov:

23: 03: 22 246 DEBUG SQL: 92 - vyberte order0_.id ako id1_2_, order0_.orderNumber ako orderNum2_2_, order0_.verziu ako version3_2_ z purchaseOrder order0_ kde order0_.id = 1 23: 03: 22,254 TRACE BasicExtractor: 61 - extrahovaná hodnota ( [id1_2_]: [BIGINT]) - [1] 23: 03: 22 261 TRACE BasicExtractor: 61 - extrahovaná hodnota ([orderNum2_2_]: [VARCHAR]) - [order1] 23: 03: 22,263 TRACE BasicExtractor: 61 - extrahovaná hodnota ( [verzia3_2_]: [INTEGER]) - [0]

Hibernate vám poskytuje oveľa viac interných informácií o a Session ak aktivujete štatistiku dlhodobého spánku. Môžete to urobiť nastavením vlastnosti systému hibernate.generate_statistics do pravdy.

Aktivujte však iba štatistiku svojho vývojového alebo testovacieho prostredia. Zhromažďovanie všetkých týchto informácií spomalí vašu aplikáciu a problémy s výkonom si môžete vytvoriť sami, ak ich aktivujete vo výrobe.

Niektoré štatistické údaje si môžete pozrieť v nasledujúcom útržku kódu:

23: 04: 12 123 INFO StatisticalLoggingSessionEventListener: 258 - Metriky relácie {23793 nanosekúnd strávených získaním 1 spojenia JDBC; 0 nanosekúnd strávených uvoľnením 0 pripojení JDBC; 39 4668 nanosekúnd strávených prípravou 4 výpisov JDBC; 2528603 nanosekúnd strávených vykonaním 4 výpisov JDBC; 0 nanosekúnd strávených vykonaním 0 dávok JDBC; 0 nanosekúnd strávených vykonaním 0 vložení L2C; 0 nanosekúnd strávených vykonaním 0 zásahov L2C; 0 nanosekúnd strávených vykonaním 0 zmeškaní L2C; 9700599 nanosekúnd strávených vykonaním 1 vyprázdnenia (vyprázdnenie celkom 9 entít a 3 zbierok); 42921 nanosekúnd strávených vykonaním 1 čiastočného vyprázdnenia (vyprázdnenie celkom 0 entít a 0 zbierok)}

Tieto štatistiky pravidelne používam pri svojej každodennej práci na hľadanie problémov s výkonom skôr, ako sa vyskytnú vo výrobe, a práve o tom by som mohol napísať niekoľko príspevkov. Poďme sa teda sústrediť len na tie najdôležitejšie.

Riadky 2 až 5 ukazujú, koľko pripojení a príkazov JDBC použil program Hibernate počas tejto relácie a koľko času tomu venoval. Mali by ste sa vždy pozrieť na tieto hodnoty a porovnať ich s vašimi očakávaniami.

Ak je výrokov oveľa viac, ako ste čakali, je pravdepodobné, že máte najbežnejší problém s výkonom, problém s výberom n + 1. Nájdete ho takmer vo všetkých aplikáciách a vo väčšej databáze by mohol spôsobiť obrovské problémy s výkonom. Túto otázku podrobnejšie vysvetľujem v nasledujúcej časti.

Riadky 7 až 9 ukazujú, ako Hibernate interagoval s vyrovnávacou pamäťou 2. úrovne. Toto je jedna z 3 pamätí Hibernate a ukladá entity nezávisle na relácii. Ak vo svojej aplikácii používate 2. úroveň, mali by ste vždy sledovať tieto štatistiky, aby ste zistili, či režim dlhodobého spánku odtiaľ dostane entity.

Konfigurácia výroby

Produkčná konfigurácia by mala byť optimalizovaná na výkon a vyhnúť sa správam, ktoré nie sú urgentne vyžadované. Vo všeobecnosti to znamená, že by ste mali zaznamenávať iba chybové správy. Ak používate Log4j, môžete to dosiahnuť pomocou nasledujúcej konfigurácie:

Ak používate Log4j, môžete to dosiahnuť pomocou nasledujúcej konfigurácie:

log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern =% d {HH: mm: ss, SSS}% -5p [% c] -% m% n log4j.rootLogger = informácie, štandardný výstup # základná úroveň protokolu pre všetky správy log4j.logger.org.hibernate = chyba

2.2. N + 1 Vyberte vydanie

Ako som už vysvetlil, problém s výberom n + 1 je najbežnejším problémom s výkonom. Mnoho vývojárov tento problém obviňuje z konceptu mapovania OR a úplne sa nemýli. Ľahko sa mu však vyhnete, ak pochopíte, ako Hibernate zaobchádza s lenivo stiahnutými vzťahmi. Preto je na vine aj vývojár, pretože je jeho zodpovednosťou vyhnúť sa týmto problémom. Najprv mi dovoľte vysvetliť, prečo tento problém existuje, a potom vám ukážem jednoduchý spôsob, ako mu zabrániť. Ak ste už oboznámení s problémami s výberom n + 1, môžete prejsť priamo na riešenie.

Režim dlhodobého spánku poskytuje veľmi pohodlné mapovanie vzťahov medzi entitami. Potrebujete iba atribút s typom súvisiacej entity a niekoľkými anotáciami, aby ste ho mohli definovať:

@Entity @Table (name = "purchaseOrder") verejná trieda Order implements Serializable {@OneToMany (mappedBy = "order", fetch = FetchType.LAZY) private Set items = new HashSet (); ...}

Keď teraz načítate objednať entita z databázy, stačí zavolať na getItems () metóda na získanie všetkých položiek tejto objednávky. Režim dlhodobého spánku skryje požadované dotazy na databázu, aby sa získali súvisiace informácie OrderItem subjekty z databázy.

Keď ste začínali s režimom dlhodobého spánku, pravdepodobne ste sa dozvedeli, že by ste mali používať FetchType.LAZY pre väčšinu vzťahov a že je predvolený pre mnoho vzťahov. Hibernate tak bude môcť načítať iba súvisiace entity, ak použijete atribút, ktorý mapuje vzťah. Načítanie iba tých údajov, ktoré potrebujete, je vo všeobecnosti dobrá vec, vyžaduje si však tiež, aby program Hibernate vykonal ďalší dotaz na inicializáciu každého vzťahu. To môže mať za následok obrovské množstvo otázok, ak pracujete na zozname entít, ako to robím v nasledujúcom útržku kódu:

Zoznam objednávok = em.createQuery ("VYBERTE O Z OBJEDNÁVKY o"). GetResultList (); pre (Objednávka objednávky: objednávky) {log.info ("Objednávka:" + order.getOrderNumber ()); log.info ("Počet položiek:" + order.getItems (). size ()); }

Pravdepodobne by ste nečakali, že týchto pár riadkov kódu dokáže vytvoriť stovky alebo dokonca tisíce databázových dotazov. Ale robí to, ak používate FetchType.LAZY pre vzťah k OrderItem subjekt:

22: 47: 30 065 DEBUG SQL: 92 - vyberte order0_.id ako id1_2_, order0_.orderNumber ako orderNum2_2_, order0_.verziu ako verziu3_2_ z nákupuObjednávka order0_ 22: 47: 30 136 INFO NamedEntityGraphTest: 58 - Objednávka: order1 22: 47: 30 140 DEBUG SQL: 92 - vyberte item0_.order_id ako order_id4_0_0_, items0_.id ako id1_0_0_, items0_.id ako id1_0_1_, items0_.order_id ako order_id4_0_1_, items0_.product_id ako produkt_5_0_1_, items0_.množstvo ako množstvo__0.0 v_množstve ako množstvo_0.0 v_množstve ako množstvo_0.0 v_množstve ako množstvo_0.0 items0_.order_id =? 22: 47: 30 171 INFO NamedEntityGraphTest: 59 - Počet položiek: 2 22: 47: 30 171 INFO NamedEntityGraphTest: 58 - Objednávka: order2 22: 47: 30 172 DEBUG SQL: 92 - vyberte items0_.order_id ako order_id4_0_0_, items0_.id ako id1_0_0 , items0_.id ako id1_0_1_, items0_.order_id ako order_id4_0_1_, items0_.product_id ako product_5_0_1_, items0_.quantity ako množstvo2_0_1_, items0_.verzia ako verzia3_0_1_ z OrderItem items0_ kde items0_.order_id =? 22: 47: 30 174 INFO NamedEntityGraphTest: 59 - Počet položiek: 2 22: 47: 30 174 INFO NamedEntityGraphTest: 58 - Objednávka: order3 22: 47: 30 174 DEBUG SQL: 92 - vyberte items0_.order_id ako order_id4_0_0_, items0_.id ako id1_0_0 , items0_.id ako id1_0_1_, items0_.order_id ako order_id4_0_1_, items0_.product_id ako product_5_0_1_, items0_.quantity ako množstvo2_0_1_, items0_.verzia ako verzia3_0_1_ z OrderItem items0_ kde items0_.order_id =? 22: 47: 30 176 INFO NamedEntityGraphTest: 59 - Počet položiek: 2

Hibernate vykoná jeden dotaz, aby získal všetky objednať subjekty a ďalší pre každú z n objednať subjekty inicializovať orderItem vzťah. Takže teraz viete, prečo sa tento druh problému nazýva n + 1 select issue a prečo môže spôsobiť obrovské problémy s výkonom.

Čo je ešte horšie, je to, že to v malej testovacej databáze často nespoznáte, ak ste si nekontrolovali štatistiku dlhodobého spánku. Útržok kódu vyžaduje iba niekoľko desiatok dotazov, ak testovacia databáza neobsahuje veľa objednávok. Ale to bude úplne iné, ak použijete svoju produktívnu databázu, ktorá ich obsahuje niekoľko tisíc.

Už som povedal, že týmto problémom sa môžete ľahko vyhnúť. A to je pravda. Musíte len inicializovať vzťah orderItem, keď vyberiete objednať subjekty z databázy.

Robte to však iba vtedy, ak používate vzťah vo svojom obchodnom kódexe a nepoužívate ho FetchType.EAGER vždy načítať súvisiace entity. To len nahradí váš problém s n + 1 iným problémom s výkonom.

Inicializovať vzťahy s a @NamedEntityGraph

Existuje niekoľko rôznych možností na inicializáciu vzťahov. Najradšej používam a @NamedEntityGraph čo je jedna z mojich obľúbených funkcií zavedená v JPA 2.1. Poskytuje nezávislým spôsobom na zadanie grafu entít, ktoré režim dlhodobého spánku načíta z databázy. V nasledujúcom útržku kódu môžete vidieť príklad jednoduchého grafu, ktorý umožňuje režimu dlhodobého spánku dychtivo načítať atribút items entity:

@Entity @Table (name = "purchase_order") @NamedEntityGraph (name = "graph.Order.items", attributeNodes = @NamedAttributeNode ("items")) verejná trieda Objednávka implementuje Serializable {...}

Na definovanie grafu entity pomocou a nie je potrebné urobiť veľa @NamedEntityGraph anotácia. Musíte len uviesť jedinečný názov grafu a jeden @NamedAttributeNode anotácia pre každý atribút Hibernate sa načítava nedočkavo. V tomto príklade je to iba atribút items, ktorý mapuje vzťah medzi objednať a niekoľko OrderItem subjekty.

Teraz môžete pomocou grafu entity riadiť načítanie alebo konkrétny dopyt. Preto musíte vytvoriť inštanciu EntityGraph založený na @NamedEntityGraph definíciu a poskytnúť ju ako pomôcku pre EntityManager.find () metóda alebo váš dotaz. Robím to v nasledujúcom útržku kódu, kde vyberiem objednať entita s ID 1 z databázy:

EntityGraph graph = this.em.getEntityGraph ("graph.Order.items"); Tipy na mapu = nový HashMap (); hints.put ("javax.persistence.fetchgraph", graf); vrátiť this.em.find (Order.class, 1L, rady);

Hibernate používa tieto informácie na vytvorenie jedného príkazu SQL, ktorý získa atribúty objednať entita a atribúty grafu entity z databázy:

17: 34: 51 310 DEBUG [org.hibernate.loader.plan.build.spi.LoadPlanTreePrinter] (pool-2-thread-1) LoadPlan (entity = blog.thoughts.on.java.jpa21.entity.graph.model. Objednávka) - Vráti - EntityReturnImpl (entity = blog.thoughts.on.java.jpa21.entity.graph.model.Order, querySpaceUid =, path = blog.thoughts.on.java.jpa21.entity.graph.model.Order) - CollectionAttributeFetchImpl (collection = blog.thoughts.on.java.jpa21.entity.graph.model.Order.items, querySpaceUid =, path = blog.thoughts.on.java.jpa21.entity.graph.model.Order.items) - (prvok kolekcie) CollectionFetchableElementEntityGraph (entity = blog.thoughts.on.java.jpa21.entity.graph.model.OrderItem, querySpaceUid =, path = blog.thoughts.on.java.jpa21.entity.graph.model.Order. items.) - EntityAttributeFetchImpl (entity = blog.thoughts.on.java.jpa21.entity.graph.model.Product, querySpaceUid =, path = blog.thoughts.on.java.jpa21.entity.graph.model.Order.items ..produkt) - QuerySpaces - EntityQuerySpaceImpl (uid =, entity = blog.thoughts.on.java.jpa21.entity.graph.model .Objednávka) - mapovanie aliasov tabuľky SQL - order0_ - aliasová prípona - 0_ - príponové stĺpce kľúčov - {id1_2_0_} - JOIN (JoinDefinedByMetadata (items)): -> - CollectionQuerySpaceImpl (uid =, collection = blog.thoughts.on.java. jpa21.entity.graph.model.Order.items) - mapovanie aliasov tabuľky SQL - items1_ - prípona aliasu - 1_ - príponové stĺpce kľúčov - {order_id4_2_1_} - prípona aliasu entity-element - 2_ - 2_entity-element prípona kľúčového stĺpca - id1_0_2_ - JOIN (JoinDefinedByMetadata (elements)): -> - EntityQuerySpaceImpl (uid =, entity = blog.thoughts.on.java.jpa21.entity.graph.model.OrderItem) - mapovanie aliasov tabuľky SQL - items1_ - alias prípona - 2_ - s príponou kľúčové stĺpce - {id1_0_2_} - JOIN (JoinDefinedByMetadata (produkt)): -> - EntityQuerySpaceImpl (uid =, entity = blog.thoughts.on.java.jpa21.entity.graph.model.Product) - mapovanie aliasov tabuľky SQL - product2_ - alias prípona - 3_ - prípony kľúčových stĺpcov - {id1_1_3_} 17:34: 51 311 DEBUG [org.hibernate.loader.entity.plan.EntityLoader] (pool-2-thread-1) statický výber f alebo entita blog. thoughts.on.java.jpa21.entity.graph.model.Order [NONE: -1]: vyberte order0_.id ako id1_2_0_, order0_.orderNumber ako orderNum2_2_0_, order0_.version ako version3_2_0_, items1_.order_id ako order_id4_2_1_ , items1_.id ako id1_0_1_, items1_.id ako id1_0_2_, items1_.order_id ako order_id4_0_2_, items1_.product_id ako product_5_0_2_, items1_.quantity ako množstvo2_0_2_, items1_.verzia ako verzia3_0_2_, product2_.id ako id1_produkt__product_id2 .verzia ako verzia3_1_3_ z purchase_order order0_ ľavé vonkajšie spojenie OrderItem items1_ na order0_.id = items1_.order_id ľavé vonkajšie spojenie Produkt product2_ na items1_.product_id = product2_.id kde order0_.id =?

Inicializácia iba jedného vzťahu je pre blogový príspevok dosť dobrá, ale v skutočnom projekte budete pravdepodobne chcieť vytvoriť zložitejšie grafy. Tak poďme na to.

Môžete samozrejme poskytnúť celý rad @NamedAttributeNode anotácie na získanie viacerých atribútov tej istej entity a môžete ich použiť @NamedSubGraph definovať načítanie pre ďalšiu úroveň entít. Používam to v nasledujúcom útržku kódu na načítanie nielen všetkých súvisiacich OrderItem subjekty, ale aj Výrobok subjekt pre každého Položka objednávky:

@Entity @Table (name = "purchase_order") @NamedEntityGraph (name = "graph.Order.items", attributeNodes = @NamedAttributeNode (value = "items", subgraph = "items"), subgraphs = @NamedSubgraph (name = " items ", attributeNodes = @NamedAttributeNode (" product "))) public class Objednávka implementuje Serializable {...}

Ako vidíte, definícia a @NamedSubGraph je veľmi podobná definícii a @NamedEntityGraph. Na tento podgraf potom môžete odkazovať v a @NamedAttributeNode anotácia, ktorá definuje načítanie pre tento konkrétny atribút.

Kombinácia týchto anotácií vám umožňuje definovať zložité grafy entít, ktoré môžete použiť na inicializáciu všetkých vzťahov, ktoré vo svojom prípade použitia použijete, a vyhnúť sa problémom s výberom n + 1. Ak chcete dynamicky špecifikovať svoj entitový graf za behu, môžete to urobiť aj prostredníctvom rozhrania Java API.

2.3. Aktualizujte entity jeden po druhom

Aktualizácia entít po jednej je veľmi prirodzená, ak myslíte objektovo. Dostanete iba entity, ktoré chcete aktualizovať, a zavoláte niekoľko metód setteru, aby ste zmenili ich atribúty, ako to robíte s akýmkoľvek iným objektom.

Tento prístup funguje dobre, ak zmeníte iba niekoľko entít.Ale stáva sa veľmi neefektívnym, keď pracujete so zoznamom entít, a je to tretí problém s výkonom, ktorý môžete ľahko zistiť vo svojom protokolovom súbore. Musíte len hľadať kopu príkazov SQL UPDATE, ktoré vyzerajú úplne rovnako, ako vidíte v nasledujúcom protokolovom súbore:

22: 58: 05 829 DEBUG SQL: 92 - vyberte product0_.id ako id1_1_, product0_.name ako name2_1_, product0_.cena ako cena3_1_, product0_.verzia ako verzia4_1_ z produktu product0_ 22: 58: 05 883 DEBUG SQL: 92 - aktualizácia sady produktov názov = ?, cena = ?, verzia =? kde id =? a verzia =? 22: 58: 05 889 DEBUG SQL: 92 - aktualizácia Názov sady produktov = ?, cena = ?, verzia =? kde id =? a verzia =? 22: 58: 05 891 DEBUG SQL: 92 - aktualizácia Názov sady produktov = ?, cena = ?, verzia =? kde id =? a verzia =? 22: 58: 05 893 DEBUG SQL: 92 - aktualizácia Názov sady produktov = ?, cena = ?, verzia =? kde id =? a verzia =? 22: 58: 05 900 DEBUG SQL: 92 - aktualizácia Názov sady produktov = ?, cena = ?, verzia =? kde id =? a verzia =?

Pre tieto prípady použitia je oveľa vhodnejšie relačné znázornenie databázových záznamov ako objektovo orientované. S SQL stačí napísať jeden príkaz SQL, ktorý aktualizuje všetky záznamy, ktoré chcete zmeniť.

To isté môžete urobiť s režimom dlhodobého spánku, ak používate JPQL, natívne SQL alebo CriteriaUpdate API. Všetky 3 veľmi podobné, takže v tomto príklade použijeme JPQL.

Príkaz JPQL UPDATE môžete definovať podobným spôsobom, ako ho poznáte z jazyka SQL. Vo vyhlásení WHERE iba definujete, ktorú entitu chcete aktualizovať, ako zmeniť hodnoty jej atribútov a obmedziť ovplyvnené entity.

Jeho príklad si môžete pozrieť v nasledujúcom útržku kódu, kde zvyšujem cenu všetkých produktov o 10%:

em.createQuery ("UPDATE Produkt p SET p.price = p.price * 0,1"). executeUpdate ();

Hibernate vytvorí príkaz SQL UPDATE na základe príkazu JPQL a odošle ho do databázy, ktorá vykonáva operáciu aktualizácie.

Je zrejmé, že tento prístup je oveľa rýchlejší, ak musíte aktualizovať obrovské množstvo entít. Má to však aj nevýhodu. Hibernate nevie, ktoré entity sú ovplyvnené operáciou aktualizácie, a neaktualizuje svoju vyrovnávaciu pamäť 1. úrovne. Mali by ste sa preto uistiť, že entitu s príkazom JPQL nečítate a neaktualizujete v rámci tej istej relácie dlhodobého spánku, alebo ju musíte odpojiť, aby ste ju odstránili z medzipamäte.

3. Zhrnutie

V rámci tohto príspevku som vám to ukázal 3 Problémy s výkonom v režime dlhodobého spánku, ktoré nájdete v súboroch denníka.

2 z nich boli spôsobené obrovským počtom príkazov SQL. Toto je častý dôvod problémov s výkonom, ak pracujete s režimom dlhodobého spánku. Hibernate skryje prístup k databáze za svojím API, a preto je často ťažké odhadnúť skutočný počet príkazov SQL. Preto by ste mali vždy vykonať vykonané príkazy SQL pri zmene úrovne vytrvalosti.


$config[zx-auto] not found$config[zx-overlay] not found