Časté výnimky z režimu dlhodobého spánku

1. Úvod

V tomto výučbe si ukážeme niekoľko bežných výnimiek, s ktorými sa môžeme stretnúť pri práci s režimom dlhodobého spánku.

Posúdime ich účel a niektoré bežné príčiny. Ďalej sa pozrieme na ich riešenia.

2. Prehľad výnimiek v režime dlhodobého spánku

Mnoho podmienok môže spôsobiť vyvolanie výnimiek počas používania režimu dlhodobého spánku. Môžu to byť chyby mapovania, problémy s infraštruktúrou, chyby SQL, narušenie integrity údajov, problémy s reláciami a chyby transakcií.

Tieto výnimky väčšinou siahajú od HibernateException. Ak však používame režim dlhodobého spánku ako poskytovateľa perzistencie JPA, tieto výnimky sa môžu zabaliť PersistenceException.

Obe tieto základné triedy siahajú od RuntimeException. Preto sú všetky nezaškrtnuté. Preto ich nemusíme chytať ani deklarovať na každom mieste, kde sa používajú.

Ďalej väčšina z nich je nedobytná. Výsledkom by bolo, že opakovanie operácie by nepomohlo. To znamená, že musíme opustiť súčasné stretnutie, keď sa s nimi stretneme.

Pozrime sa teraz na každú z nich, jednu po druhej.

3. Mapovacie chyby

Objektovo-relačné mapovanie je hlavnou výhodou režimu dlhodobého spánku. Konkrétne nás to oslobodzuje od ručného písania príkazov SQL.

Zároveň vyžaduje, aby sme špecifikovali mapovanie medzi objektmi Java a databázovými tabuľkami. Podľa toho ich špecifikujeme pomocou anotácií alebo prostredníctvom mapovacích dokumentov. Tieto mapovania je možné kódovať manuálne. Prípadne môžeme na ich generovanie použiť nástroje.

Pri určovaní týchto mapovaní môžeme robiť chyby. Môžu byť v špecifikácii mapovania. Alebo môže dôjsť k nesúladu medzi objektom Java a zodpovedajúcou databázovou tabuľkou.

Takéto chyby mapovania vytvárajú výnimky. Počas počiatočného vývoja sa s nimi stretávame často. Okrem toho na ne môžeme naraziť pri migrácii zmien v rôznych prostrediach.

Pozrime sa na tieto chyby na niekoľkých príkladoch.

3.1. MappingException

Problém s objektovo-relačným mapovaním spôsobuje a MappingException byť vyhodený:

public void whenQueryExecutedWithUnmappedEntity_thenMappingException () {thrown.expectCause (isA (MappingException.class)); thrown.expectMessage ("Neznáma entita: java.lang.String"); Relácia session = sessionFactory.getCurrentSession (); NativeQuery query = session .createNativeQuery ("vyberte názov z produktu PRODUCT", String.class); query.getResultList (); }

Vo vyššie uvedenom kóde je createNativeQuery metóda sa pokúša mapovať výsledok dotazu na zadaný typ Java String. Využíva implicitné mapovanie String trieda z Metamodel urobiť mapovanie.

Avšak String trieda nemá zadané žiadne mapovanie. Preto Hibernate nevie, ako zmapovať názov stĺpec do String a hodí výnimku.

Podrobnú analýzu možných príčin a riešení nájdete v dokumente Výnimka mapovania režimu dlhodobého spánku - neznáma entita.

Túto výnimku môžu spôsobiť aj ďalšie chyby:

  • Miešanie anotácií k poliam a metódam
  • Neuvádza sa @JoinTable pre @ManyToMany združenie
  • Predvolený konštruktor mapovanej triedy vyvolá počas spracovania mapovania výnimku

Ďalej MappingException má niekoľko podtried, ktoré môžu naznačovať konkrétne problémy s mapovaním:

  • AnnotationException - problém s anotáciou
  • DuplicateMappingException - duplicitné mapovanie pre triedu, tabuľku alebo názov vlastnosti
  • InvalidMappingException - mapovanie je neplatné
  • MappingNotFoundException - mapovací zdroj sa nepodarilo nájsť
  • PropertyNotFoundException - v triede sa nepodarilo nájsť očakávanú metódu getra alebo setra

Preto ak narazíme na túto výnimku, mali by sme si najskôr overiť naše priradenia.

3.2. AnnotationException

Aby sme pochopili Výnimka z anotácie, vytvorme entitu bez anotácie identifikátora pre akékoľvek pole alebo vlastnosť:

@Entity verejná trieda EntityWithNoId {private int id; public int getId () {return id; } // štandardný nastavovač}

Odkedy Hibernácia očakáva, že každá entita bude mať identifikátor, dostaneme AnnotationException keď použijeme entitu:

public void givenEntityWithoutId_whenSessionFactoryCreated_thenAnnotationException () {thrown.expect (AnnotationException.class); thrown.expectMessage ("Pre entitu nebol zadaný žiadny identifikátor"); Konfigurácia cfg = getConfiguration (); cfg.addAnnotatedClass (EntityWithNoId.class); cfg.buildSessionFactory (); }

Ďalej sú niektoré ďalšie pravdepodobné príčiny:

  • Neznámy generátor sekvencií používaný v @GeneratedValue anotácia
  • @ Temporal anotácia použitá v prostredí Java 8 Dátum/Čas trieda
  • Cieľová entita chýba pre alebo neexistuje @ManyToOne alebo @OneToMany
  • Triedy prvotného zberu používané s anotáciami vzťahov @OneToMany alebo @ManyToMany
  • Konkrétne triedy použité s anotáciami zbierky @OneToMany, @ManyToMany alebo @ElementCollection pretože Hibernate očakáva zberové rozhrania

Aby sme túto výnimku vyriešili, mali by sme najskôr skontrolovať konkrétnu anotáciu uvedenú v chybovej správe.

4. Chyby správy schémy

Automatická správa schémy databázy je ďalšou výhodou režimu dlhodobého spánku. Môže napríklad generovať príkazy DDL na vytváranie alebo overovanie databázových objektov.

Ak chcete používať túto funkciu, musíme nastaviť prezimovat.hbm2ddl.auto majetok primerane.

Ak sa pri vykonávaní správy schém vyskytujú problémy, dostaneme výnimku. Poďme preskúmať tieto chyby.

4.1. SchemaManagementException

Akýkoľvek problém súvisiaci s infraštruktúrou pri vykonávaní správy schém spôsobuje a SchemaManagementException.

Na ukážku dáme príkazu Hibernate overiť databázovú schému:

public void givenMissingTable_whenSchemaValidated_thenSchemaManagementException () {thrown.expect (SchemaManagementException.class); thrown.expectMessage ("Validácia schémy: chýbajúca tabuľka"); Konfigurácia cfg = getConfiguration (); cfg.setProperty (AvailableSettings.HBM2DDL_AUTO, "overiť"); cfg.addAnnotatedClass (Product.class); cfg.buildSessionFactory (); }

Pretože tabuľka zodpovedajúca Výrobok nie je prítomný v databáze, dostaneme výnimku validácie schémy pri vytváraní SessionFactory.

Pre túto výnimku existujú ďalšie možné scenáre:

  • sa nemôže pripojiť k databáze na vykonávanie úloh správy schémy
  • schéma nie je v databáze

4.2. CommandAcceptanceException

Akýkoľvek problém so spustením DDL zodpovedajúcim konkrétnemu príkazu na správu schémy môže spôsobiť a CommandAcceptanceException.

Ako príklad uveďme nesprávny dialekt pri nastavovaní SessionFactory:

public void whenWrongDialectSpecified_thenCommandAcceptanceException () {thrown.expect (SchemaManagementException.class); thrown.expectCause (isA (CommandAcceptanceException.class)); thrown.expectMessage ("Zastavenie pri chybe: Chyba pri vykonávaní DDL"); Konfigurácia cfg = getConfiguration (); cfg.setProperty (AvailableSettings.DIALECT, "org.hibernate.dialect.MySQLDialect"); cfg.setProperty (AvailableSettings.HBM2DDL_AUTO, "aktualizácia"); cfg.setProperty (AvailableSettings.HBM2DDL_HALT_ON_ERROR, "true"); cfg.getProperties () .put (AvailableSettings.HBM2DDL_HALT_ON_ERROR, true); cfg.addAnnotatedClass (Product.class); cfg.buildSessionFactory (); }

Tu sme zadali nesprávny dialekt: MySQLDialect. Tiež dávame príkazu Hibernate aktualizovať objekty schémy. V dôsledku toho zlyhajú príkazy DDL vykonané programom Hibernate na aktualizáciu databázy H2 a dostaneme výnimku.

V predvolenom nastavení režim dlhodobého spánku ticho zaznamená túto výnimku a pokračuje ďalej. Keď neskôr použijeme SessionFactory, dostaneme výnimku.

Nastavili sme vlastnosť, aby sme sa uistili, že pri tejto chybe dôjde k výnimke HBM2DDL_HALT_ON_ERROR do pravda.

Podobne sú uvedené aj ďalšie bežné príčiny tejto chyby:

  • Názvy stĺpcov sa medzi mapovaním a databázou nezhodujú
  • Dve triedy sú mapované do tej istej tabuľky
  • Názov použitý pre triedu alebo tabuľku je napríklad rezervované slovo v databáze UŽÍVATEĽ, napríklad
  • Používateľ použitý na pripojenie k databáze nemá požadované oprávnenie

5. Chyby pri vykonávaní SQL

Keď vkladáme, aktualizujeme, odstraňujeme alebo dopytujeme údaje pomocou režimu dlhodobého spánku, vykonáva príkazy DML proti databáze pomocou JDBC. Toto API zvyšuje SQLException ak operácia vedie k chybám alebo varovaniam.

Režim dlhodobého spánku prevádza túto výnimku na JDBCException alebo jedna z jeho vhodných podtried:

  • ConstraintViolationException
  • DataException
  • JDBCConnectionException
  • LockAcquisitionException
  • PessimisticLockException
  • QueryTimeoutException
  • SQLGrammarException
  • Generická výnimka JDBCE

Poďme diskutovať o bežných chybách.

5.1. JDBCException

JDBCException je vždy spôsobený konkrétnym príkazom SQL. Môžeme zavolať getSQL metóda na získanie problematického príkazu SQL.

Ďalej môžeme načítať podkladové materiály SQLException s getSQLException metóda.

5.2. SQLGrammarException

SQLGrammarException označuje, že SQL odoslaný do databázy bol neplatný. Môže to byť spôsobené chybou syntaxe alebo neplatným odkazom na objekt.

Napríklad, chýbajúca tabuľka môže mať za následok túto chybu pri vyhľadávaní údajov:

public void givenMissingTable_whenQueryExecuted_thenSQLGrammarException () {thrown.expect (isA (PersistenceException.class)); thrown.expectCause (isA (SQLGrammarException.class)); thrown.expectMessage ("SQLGrammarException: príkaz sa nepodarilo pripraviť"); Relácia session = sessionFactory.getCurrentSession (); NativeQuery query = session.createNativeQuery ("select * from NON_EXISTING_TABLE", Product.class); query.getResultList (); }

Túto chybu môžeme získať aj pri ukladaní údajov, ak tabuľka chýba:

public void givenMissingTable_whenEntitySaved_thenSQLGrammarException () {thrown.expect (isA (PersistenceException.class)); thrown.expectCause (isA (SQLGrammarException.class)); vyhodené .expectMessage ("SQLGrammarException: príkaz sa nepodarilo pripraviť"); Konfigurácia cfg = getConfiguration (); cfg.addAnnotatedClass (Product.class); SessionFactory sessionFactory = cfg.buildSessionFactory (); Relácia relácie = null; Transakčná transakcia = null; try {session = sessionFactory.openSession (); transakcia = session.beginTransaction (); Produkt produkt = nový Produkt (); product.setId (1); product.setName ("Produkt 1"); session.save (produkt); transaction.commit (); } catch (Výnimka e) {rollbackTransactionQuietly (transakcia); hod (e); } konečne {closeSessionQuietly (relácia); closeSessionFactoryQuietly (sessionFactory); }}

Niektoré ďalšie možné príčiny sú:

  • Použitá stratégia pomenovania nemapuje triedy na správne tabuľky
  • Stĺpec uvedený v @JoinColumn neexistuje

5.3. ConstraintViolationException

A ConstraintViolationException označuje, že požadovaná operácia DML spôsobila porušenie obmedzenia integrity. Názov tohto obmedzenia môžeme získať zavolaním getConstraintName metóda.

Bežnou príčinou tejto výnimky je pokus o uloženie duplicitných záznamov:

public void whenDuplicateIdSaved_thenConstraintViolationException () {thrown.expect (isA (PersistenceException.class)); thrown.expectCause (isA (ConstraintViolationException.class)); thrown.expectMessage ("ConstraintViolationException: príkaz nemohol vykonať"); Relácia relácie = null; Transakčná transakcia = null; for (int i = 1; i <= 2; i ++) {try {session = sessionFactory.openSession (); transakcia = session.beginTransaction (); Produkt produkt = nový Produkt (); product.setId (1); product.setName ("Produkt" + i); session.save (produkt); transaction.commit (); } catch (Výnimka e) {rollbackTransactionQuietly (transakcia); hod (e); } konečne {closeSessionQuietly (relácia); }}}

Tiež ukladanie a nulový hodnota do a NIE NULL stĺpec v databáze môže túto chybu zvýšiť.

S cieľom vyriešiť túto chybu, mali by sme vykonať všetky validácie v obchodnej vrstve. Okrem toho by sa na overovanie aplikácií nemali používať obmedzenia databázy.

5.4. DataException

DataException označuje, že vyhodnotenie príkazu SQL malo za následok nejakú nelegálnu operáciu, nesúlad typu alebo nesprávnu mohutnosť.

Túto chybu môže spôsobiť napríklad použitie znakových údajov oproti číselnému stĺpcu:

public void givenQueryWithDataTypeMismatch_WhenQueryExecuted_thenDataException () {thrown.expectCause (isA (DataException.class)); thrown.expectMessage ("org.hibernate.exception.DataException: nemohol pripraviť výpis"); Relácia session = sessionFactory.getCurrentSession (); NativeQuery query = session.createNativeQuery ("select * from PRODUCT where", Product.class); query.getResultList (); }

Ak chcete opraviť túto chybu, mali by sme zabezpečiť, aby sa dátové typy a dĺžka zhodovali medzi kódom aplikácie a databázou.

5.5. JDBCConnectionException

A JDBCConectionException označuje problémy pri komunikácii s databázou.

Napríklad výpadok databázy alebo siete môže spôsobiť vyvolanie tejto výnimky.

Túto výnimku môže spôsobiť aj nesprávne nastavenie databázy. Jedným z takýchto prípadov je databázové pripojenie, ktoré server uzatvára, pretože bolo dlho nečinné. To sa môže stať, ak používame združovanie pripojení a nastavenie časového limitu nečinnosti vo fonde je viac ako hodnota časového limitu pripojenia v databáze.

Pri riešení tohto problému by sme sa mali najskôr ubezpečiť, že je hostiteľ databázy prítomný a že je funkčný. Potom by sme mali skontrolovať, či sa pre pripojenie k databáze používa správne overenie. Nakoniec by sme mali skontrolovať, či je hodnota časového limitu správne nastavená vo fonde pripojení.

5.6. QueryTimeoutException

Keď vyprší časový limit databázového dotazu, dostaneme túto výnimku. Vidíme to aj kvôli ďalším chybám, ako je napríklad naplnenie tabuľkového priestoru.

Toto je jedna z mála obnoviteľných chýb, čo znamená, že môžeme príkaz zopakovať v tej istej transakcii.

Ak chcete tento problém vyriešiť, môžeme zvýšiť časový limit dotazu pre dlhotrvajúce dotazy niekoľkými spôsobmi:

  • Nastaviť čas vypršal prvok v a @NamedQuery alebo @NamedNativeQuery anotácia
  • Vyvolajte setHint metóda dopyt rozhranie
  • Zavolajte setTimeout metóda Transakcia rozhranie
  • Vyvolajte setTimeout metóda Dopyt rozhranie

6. Chyby súvisiace so stavom relácie

Pozrime sa teraz na chyby spôsobené chybami používania relácie dlhodobého spánku.

6.1. NonUniqueObjectException

Hibernate neumožňuje dva objekty s rovnakým identifikátorom v jednej relácii.

Ak sa pokúsime spojiť dve inštancie tej istej triedy Java s rovnakým identifikátorom v jednej relácii, dostaneme a NonUniqueObjectException. Názov a identifikátor entity môžeme získať zavolaním na getEntityName () a getIdentifier () metódy.

Ak chcete túto chybu reprodukovať, pokúsime sa uložiť dve inštancie Výrobok s rovnakým ID pri relácii:

public void givenSessionContainingAnId_whenIdAssociatedAgain_thenNonUniqueObjectException () {thrown.expect (isA (NonUniqueObjectException.class)); thrown.expectMessage ("K relácii už bol priradený iný objekt s rovnakou hodnotou identifikátora"); Relácia relácie = null; Transakčná transakcia = null; try {session = sessionFactory.openSession (); transakcia = session.beginTransaction (); Produkt produkt = nový Produkt (); product.setId (1); product.setName ("Produkt 1"); session.save (produkt); product = new Product (); product.setId (1); product.setName ("Produkt 2"); session.save (produkt); transaction.commit (); } catch (Výnimka e) {rollbackTransactionQuietly (transakcia); hod (e); } konečne {closeSessionQuietly (relácia); }}

Dostaneme a NonUniqueObjectException, podľa očakávania.

Táto výnimka sa vyskytuje často pri opätovnom pripojení odpojeného objektu k relácii volaním súboru aktualizovať metóda. Ak má relácia načítanú inú inštanciu s rovnakým identifikátorom, zobrazí sa nám táto chyba. Aby sme to napravili, môžeme použiť zlúčiť metóda na opätovné pripojenie odpojeného objektu.

6.2. StaleStateException

Zimné hody StaleStateExceptions keď zlyhá kontrola čísla verzie alebo časovej pečiatky. Znamená to, že relácia obsahovala zastarané údaje.

Niekedy sa to zabalí do OptimisticLockException.

K tejto chybe zvyčajne dochádza pri používaní dlhotrvajúcich transakcií s riadením verzií.

Okrem toho sa to môže stať aj pri pokuse o aktualizáciu alebo odstránenie entity, ak príslušný riadok databázy neexistuje:

public void whenUpdatingNonExistingObject_thenStaleStateException () {thrown.expect (isA (OptimisticLockException.class)); thrown.expectMessage ("Dávková aktualizácia vrátila neočakávaný počet riadkov z aktualizácie"); thrown.expectCause (isA (StaleStateException.class)); Relácia relácie = null; Transakčná transakcia = null; try {session = sessionFactory.openSession (); transakcia = session.beginTransaction (); Produkt produkt = nový Produkt (); product.setId (15); product.setName ("Product1"); session.update (produkt); transaction.commit (); } catch (Výnimka e) {rollbackTransactionQuietly (transakcia); hod (e); } konečne {closeSessionQuietly (relácia); }}

Niektoré ďalšie možné scenáre:

  • pre entitu sme neurčili správnu stratégiu neuložených hodnôt
  • dvaja používatelia sa pokúsili odstrániť ten istý riadok v takmer rovnakom čase
  • ručne sme nastavili hodnotu v poli s automaticky generovaným ID alebo verziou

7. Lenivé inicializačné chyby

Zvyčajne konfigurujeme asociácie tak, aby sa načítali lenivo, aby sme zlepšili výkon aplikácií. Priradenia sa načítajú iba pri prvom použití.

Hibernate však na načítanie údajov vyžaduje aktívnu reláciu. Ak je relácia už uzavretá, keď sa pokúšame získať prístup k neinicializovanému združeniu, dostaneme výnimku.

Pozrime sa na túto výnimku a rôzne spôsoby, ako to napraviť.

7.1. LazyInitializationException

LazyInitializationException označuje pokus o načítanie neinicializovaných údajov mimo aktívnu reláciu. Túto chybu môžeme dostať v mnohých scenároch.

Najprv môžeme túto výnimku získať pri prístupe k lenivému vzťahu v prezentačnej vrstve. Dôvod je ten, že entita bola čiastočne načítaná v obchodnej vrstve a relácia bola uzavretá.

Po druhé, môžeme túto chybu získať pomocou Spring Data, ak použijeme getOne metóda. Táto metóda lenivo načíta inštanciu.

Existuje mnoho spôsobov, ako vyriešiť túto výnimku.

V prvom rade môžeme všetky vzťahy nedočkavo načítať.To by však malo vplyv na výkon aplikácie, pretože budeme načítať údaje, ktoré sa nebudú používať.

Po druhé, reláciu môžeme nechať otvorenú, kým sa zobrazenie nevykreslí. Toto sa nazýva „Otvorte reláciu v zobrazení”A je to anti-vzor. Mali by sme sa tomu vyhnúť, pretože to má niekoľko nevýhod.

Po tretie, môžeme otvoriť ďalšiu reláciu a znovu pripojiť entitu, aby sa získali vzťahy. Môžeme tak urobiť pomocou zlúčiť metóda na relácii.

Na záver môžeme inicializovať požadované asociácie v obchodných vrstvách. Budeme o tom diskutovať v nasledujúcej časti.

7.2. Inicializácia relevantných lenivých vzťahov v obchodnej vrstve

Existuje mnoho spôsobov, ako inicializovať lenivé vzťahy.

Jednou z možností je ich inicializácia vyvolaním zodpovedajúcich metód na entite. V takom prípade Hibernate vydá viacnásobné databázové dotazy, ktoré spôsobia znížený výkon. Hovoríme o ňom ako o probléme „N + 1 VÝBER“.

Po druhé, môžeme použiť Načítať spojenie získať údaje v jednom dotaze. Aby sme to však dosiahli, musíme napísať vlastný kód.

Nakoniec môžeme použiť grafy entít na definovanie všetkých atribútov, ktoré sa majú načítať. Môžeme použiť anotácie @NamedEntityGraph, @NamedAttributeNodea @NamedEntitySubgraph deklaratívne definovať entitový graf. Môžeme ich tiež definovať programovo pomocou API JPA. Potom, celý graf načítame v jednom volaní tak, že ho zadáme v operácii načítania.

8. Problémy s transakciami

Transakcie definujú jednotky práce a izoláciu medzi súbežnými činnosťami. Môžeme ich vymedziť dvoma rôznymi spôsobmi. Najskôr ich môžeme definitívne definovať pomocou anotácií. Po druhé, môžeme ich programovo spravovať pomocou rozhrania Hibernate Transaction API.

Ďalej režim dlhodobého spánku deleguje správu transakcií na správcu transakcií. Ak sa transakcia z nejakého dôvodu nemohla začať, potvrdiť alebo vrátiť späť, režim dlhodobého spánku vyvolá výnimku.

Spravidla dostaneme a TransactionException alebo an IllegalArgumentException v závislosti od správcu transakcií.

Na ilustráciu sa pokúsime spáchať transakciu, ktorá bola označená ako rollback:

public void givenTxnMarkedRollbackOnly_whenCommit_thenTransactionException () {thrown.expect (isA (TransactionException.class)); thrown.expectMessage ("Transakcia bola označená iba pre vrátenie späť; nemôže sa zaviazať"); Relácia relácie = null; Transakčná transakcia = null; try {session = sessionFactory.openSession (); transakcia = session.beginTransaction (); Produkt produkt = nový Produkt (); product.setId (15); product.setName ("Product1"); session.save (produkt); transaction.setRollbackOnly (); transaction.commit (); } catch (Výnimka e) {rollbackTransactionQuietly (transakcia); hod (e); } konečne {closeSessionQuietly (relácia); }}

Podobne môžu spôsobiť výnimku aj ďalšie chyby:

  • Miešanie deklaratívnych a programových transakcií
  • Pokus o začatie transakcie, keď je v relácii už aktívna iná
  • Pokus o potvrdenie alebo odvolanie bez začatia transakcie
  • Pokus o vykonanie alebo vrátenie transakcie niekoľkokrát

9. Problémy so súbežnosťou

Hibernate podporuje dve stratégie uzamykania, aby sa zabránilo nekonzistencii databázy v dôsledku súbežných transakcií - optimistická a pesimistická. Obaja uplatňujú výnimku v prípade konfliktu zamykania.

Na podporu vysokej súbežnosti a vysokej škálovateľnosti zvyčajne používame optimistické riadenie súbežnosti s kontrolou verzie. Na zisťovanie konfliktných aktualizácií sa používajú čísla verzií alebo časové značky.

OptimisticLockingException je vrhnuté na označenie optimistického konfliktu zamykania. Túto chybu napríklad dostaneme, ak vykonáme dve aktualizácie alebo odstránenie tej istej entity bez jej obnovenia po prvej operácii:

public void whenDeletingADeletedObject_thenOptimisticLockException () {thrown.expect (isA (OptimisticLockException.class)); thrown.expectMessage ("Dávková aktualizácia vrátila neočakávaný počet riadkov z aktualizácie"); thrown.expectCause (isA (StaleStateException.class)); Relácia relácie = null; Transakčná transakcia = null; try {session = sessionFactory.openSession (); transakcia = session.beginTransaction (); Produkt produkt = nový Produkt (); product.setId (12); product.setName ("Produkt 12"); session.save (produkt1); transaction.commit (); session.close (); session = sessionFactory.openSession (); transakcia = session.beginTransaction (); product = session.get (Product.class, 12); session.createNativeQuery ("vymazať z produktu, kde id = 12") .executeUpdate (); // Musíme chybu opraviť, aby sme ju obnovili. // session.refresh (produkt); session.delete (produkt); transaction.commit (); } catch (Výnimka e) {rollbackTransactionQuietly (transakcia); hod (e); } konečne {closeSessionQuietly (relácia); }}

Rovnako môžeme túto chybu získať, ak sa dvaja používatelia pokúsia aktualizovať rovnakú entitu takmer v rovnakom čase. V takom prípade môže byť prvý úspešný a druhý túto chybu vyvolá.

Preto tejto chybe sa nemôžeme úplne vyhnúť bez zavedenia pesimistického zamykania. Pravdepodobnosť jeho výskytu však môžeme minimalizovať nasledujúcim spôsobom:

  • Udržujte operácie aktualizácie čo najkratšie
  • Aktualizujte reprezentácie entít v klientovi čo najčastejšie
  • Neukládajte do vyrovnávacej pamäte entitu ani žiadny hodnotový objekt, ktorý ju predstavuje
  • Po aktualizácii vždy obnovte reprezentáciu entity na klientovi

10. Záver

V tomto článku sme sa zaoberali niektorými bežnými výnimkami, ktoré sa vyskytli pri používaní režimu dlhodobého spánku. Ďalej sme skúmali ich pravdepodobné príčiny a riešenia.

Celý zdrojový kód nájdete ako obvykle na GitHub.


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