Uobičajene iznimke hibernacije

1. Uvod

U ovom uputstvu razmotrit ćemo neke uobičajene iznimke s kojima se možemo susresti tijekom rada s hibernacijom.

Pregledat ćemo njihovu svrhu i neke uobičajene uzroke. Uz to ćemo razmotriti njihova rješenja.

2. Pregled iznimke hibernacije

Mnogi uvjeti mogu uzrokovati izuzeće tijekom korištenja hibernacije. To mogu biti pogreške mapiranja, infrastrukturni problemi, SQL pogreške, kršenje integriteta podataka, problemi sesije i pogreške transakcije.

Te se iznimke uglavnom protežu od HibernateException. Međutim, ako Hibernate koristimo kao pružatelja trajnosti JPA, ove se iznimke mogu umotati PerzistentnostIznimka.

Obje ove osnovne klase protežu se od RuntimeException. Stoga su svi oni neprovjereni. Stoga ih ne trebamo hvatati ili prijavljivati ​​na svakom mjestu na kojem se koriste.

Nadalje, većina njih je nepopravljiva. Kao rezultat, ponovni pokušaj operacije ne bi pomogao. To znači da moramo napustiti trenutnu sesiju kada se susretnemo s njima.

Pogledajmo sada svaku od njih, jednu po jednu.

3. Mapiranje pogrešaka

Objektno-relacijsko mapiranje glavna je prednost hibernacije. Točnije, oslobađa nas ručnog pisanja SQL izraza.

Istodobno, zahtijeva da odredimo mapiranje između Java objekata i tablica baze podataka. U skladu s tim, mi ih određujemo pomoću bilješki ili putem mapiranja dokumenata. Ta se mapiranja mogu ručno kodirati. Za njihovo generiranje možemo koristiti alate.

Dok specificiramo ova preslikavanja, možemo pogriješiti. To bi moglo biti u specifikaciji mapiranja. Ili može doći do neusklađenosti između Java objekta i odgovarajuće tablice baze podataka.

Takve pogreške mapiranja generiraju iznimke. Često ih susrećemo tijekom početnog razvoja. Uz to, možemo ih naletjeti tijekom migracije promjena u različitim okruženjima.

Pogledajmo ove pogreške s nekoliko primjera.

3.1. MappingException

Problem s objektno-relacijskim mapiranjem uzrokuje a MappingException biti bačen:

javna praznina whenQueryExecutedWithUnmappedEntity_thenMappingException () {thrown.expectCause (isA (MappingException.class)); thrown.expectMessage ("Nepoznati entitet: java.lang.String"); Sjednica sesije = sessionFactory.getCurrentSession (); NativeQuery upit = session .createNativeQuery ("odaberite ime iz PROIZVODA", String.class); query.getResultList (); }

U gornjem kodu, createNativeQuery metoda pokušava preslikati rezultat upita na navedenu vrstu Java Niz. Koristi implicitno mapiranje Niz razred iz Metamodel napraviti mapiranje.

Međutim Niz klasa nema specificirano mapiranje. Stoga Hibernate ne zna kako mapirati mapu Ime stupac do Niz i baca iznimku.

Za detaljnu analizu mogućih uzroka i rješenja pogledajte Hibernate Mapping Exception - Nepoznati entitet.

Slično tome, i druge pogreške mogu uzrokovati ovu iznimku:

  • Miješanje napomena na poljima i metodama
  • Neuspjeh u specificiranju @JoinTable za @ManyToMany udruživanje
  • Zadani konstruktor preslikane klase baca iznimku tijekom obrade preslikavanja

Nadalje, MappingException ima nekoliko potklasa koje mogu ukazivati ​​na određene probleme s mapiranjem:

  • AnnotationException - problem s bilješkom
  • DuplicateMappingException - dvostruko mapiranje za naziv klase, tablice ili svojstva
  • InvalidMappingException - mapiranje je nevaljano
  • MappingNotFoundException - Resurs za mapiranje nije pronađen
  • PropertyNotFoundException - očekivani način dobivanja ili postavljanja nije moguće pronaći na klasi

Stoga, ako naiđemo na ovu iznimku, prvo bismo trebali provjeriti svoja mapiranja.

3.2. AnnotationException

Da biste razumjeli AnnotationException, stvorimo entitet bez oznake identifikatora na bilo kojem polju ili svojstvu:

@Entity javna klasa EntityWithNoId {private int id; public int getId () {return id; } // standardni postavljač}

Od Hibernate očekuje da svaki entitet ima identifikator, dobit ćemo AnnotationException kada koristimo entitet:

javna praznina givenEntityWithoutId_whenSessionFactoryCreated_thenAnnotationException () {thrown.expect (AnnotationException.class); thrown.expectMessage ("Nije naveden identifikator za entitet"); Konfiguracija cfg = getConfiguration (); cfg.addAnnotatedClass (EntityWithNoId.class); cfg.buildSessionFactory (); }

Nadalje, neki drugi vjerojatni uzroci su:

  • Nepoznati generator sljedova korišten u @GeneratedValue bilješka
  • @Temporal napomena koja se koristi s Javom 8 Datum/Vrijeme razred
  • Ciljani entitet nedostaje ili uopće ne postoji za @ManyToOne ili @OneToMany
  • Klase sirovih zbirki koje se koriste s oznakama odnosa @OneToMany ili @ManyToMany
  • Konkretni razredi koji se koriste s bilješkama zbirke @OneToMany, @ManyToMany ili @ElementCollection kao što Hibernate očekuje sučelja za prikupljanje

Da bismo riješili ovu iznimku, prvo bismo trebali provjeriti određenu napomenu spomenutu u poruci pogreške.

4. Pogreške upravljanja shemom

Automatsko upravljanje shemom baze podataka još je jedna prednost hibernacije. Na primjer, može generirati DDL izjave za stvaranje ili provjeru valjanosti objekata baze podataka.

Da bismo koristili ovu značajku, moramo postaviti zimski san.hbm2ddl.auto vlasništvo primjereno.

Ako postoje problemi tijekom izvođenja upravljanja shemom, dobit ćemo iznimku. Ispitajmo ove pogreške.

4.1. SchemaManagementException

Bilo koji problem povezan s infrastrukturom u izvođenju upravljanja shemama uzrokuje a SchemaManagementException.

Da bismo demonstrirali, uputimo Hibernate da provjeri valjanost sheme baze podataka:

javna praznina givenMissingTable_whenSchemaValidated_thenSchemaManagementException () {thrown.expect (SchemaManagementException.class); thrown.expectMessage ("Provjera sheme: nedostaje tablica"); Konfiguracija cfg = getConfiguration (); cfg.setProperty (AvailableSettings.HBM2DDL_AUTO, "provjeri valjanost"); cfg.addAnnotatedClass (Product.class); cfg.buildSessionFactory (); }

Budući da tablica koja odgovara Proizvod nije prisutan u bazi podataka, dobit ćemo iznimku provjere sheme tijekom izrade SessionFactory.

Uz to, postoje i drugi mogući scenariji za ovu iznimku:

  • ne može se povezati s bazom podataka za obavljanje zadataka upravljanja shemom
  • shema nije prisutna u bazi podataka

4.2. CommandAcceptanceException

Bilo koji problem s izvršavanjem DDL-a koji odgovara određenoj naredbi za upravljanje shemom može uzrokovati CommandAcceptanceException.

Kao primjer, navedimo pogrešni dijalekt tijekom postavljanja SjednicaTvornica:

javna praznina whenWrongDialectSpecified_thenCommandAcceptanceException () {thrown.expect (SchemaManagementException.class); thrown.expectCause (isA (CommandAcceptanceException.class)); thrown.expectMessage ("Zaustavljanje zbog pogreške: pogreška u izvršavanju DDL-a"); Konfiguracija cfg = getConfiguration (); cfg.setProperty (AvailableSettings.DIALECT, "org.hibernate.dialect.MySQLDialect"); cfg.setProperty (AvailableSettings.HBM2DDL_AUTO, "update"); cfg.setProperty (AvailableSettings.HBM2DDL_HALT_ON_ERROR, "true"); cfg.getProperties () .put (AvailableSettings.HBM2DDL_HALT_ON_ERROR, true); cfg.addAnnotatedClass (Product.class); cfg.buildSessionFactory (); }

Ovdje smo naveli pogrešan dijalekt: MySQLDialect. Također, upućujemo Hibernate da ažurira objekte sheme. Slijedom toga, DDL izrazi koje je Hibernate izvršio za ažuriranje baze podataka H2 neće uspjeti i dobit ćemo iznimku.

Prema zadanim postavkama Hibernate tiho bilježi ovu iznimku i nastavlja dalje. Kad kasnije koristimo Tvornica sesije, dobivamo iznimku.

Da bismo osigurali da se na ovu pogrešku pojavi iznimka, postavili smo svojstvo HBM2DDL_HALT_ON_ERROR do pravi.

Slično su i neki drugi uobičajeni uzroci ove pogreške:

  • Postoji nepodudaranje imena stupaca između mapiranja i baze podataka
  • Dvije su klase mapirane u isti stol
  • Naziv koji se koristi za klasu ili tablicu rezervirana je riječ u bazi podataka, poput KORISNIK, na primjer
  • Korisnik koji se koristi za povezivanje s bazom podataka nema potrebne privilegije

5. Pogreške izvršavanja SQL-a

Kada umetnemo, ažuriramo, izbrišemo ili upitamo podatke pomoću hibernacije, on izvršava DML izraze protiv baze podataka koristeći JDBC. Ovaj API podiže SQLException ako operacija rezultira pogreškama ili upozorenjima.

Hibernate pretvara ovu iznimku u JDBCException ili jedna od njegovih prikladnih potklasa:

  • ConstraintViolationException
  • DataException
  • JDBCConnectionException
  • LockAcquisitionException
  • PessimisticLockException
  • QueryTimeoutException
  • SQLGrammarException
  • GeneričkiJDBCException

Razgovarajmo o uobičajenim pogreškama.

5.1. JDBCException

JDBCException je uvijek uzrokovan određenim SQL izrazom. Možemo nazvati getSQL metoda za dobivanje uvredljivog SQL izraza.

Nadalje, možemo pronaći osnovno SQLException s getSQLException metoda.

5.2. SQLGrammarException

SQLGrammarException označava da je SQL poslan u bazu podataka nevaljan. Uzrok tome može biti sintaksna pogreška ili nevaljana referenca objekta.

Na primjer, tablica koja nedostaje može rezultirati ovom pogreškom tijekom upita podataka:

javna praznina givenMissingTable_whenQueryExecuted_thenSQLGrammarException () {thrown.expect (isA (PersistenceException.class)); thrown.expectCause (isA (SQLGrammarException.class)); thrown.expectMessage ("SQLGrammarException: ne može pripremiti izjavu"); Sjednica sesije = sessionFactory.getCurrentSession (); NativeQuery query = session.createNativeQuery ("select * from NON_EXISTING_TABLE", Product.class); query.getResultList (); }

Također, ovu pogrešku možemo dobiti tijekom spremanja podataka ako nedostaje tablica:

javna praznina givenMissingTable_whenEntitySaved_thenSQLGrammarException () {thrown.expect (isA (PersistenceException.class)); thrown.expectCause (isA (SQLGrammarException.class)); bačeno .expectMessage ("SQLGrammarException: ne može pripremiti izjavu"); Konfiguracija cfg = getConfiguration (); cfg.addAnnotatedClass (Product.class); SessionFactory sessionFactory = cfg.buildSessionFactory (); Sjednica sesije = null; Transakcijska transakcija = null; isprobajte {session = sessionFactory.openSession (); transakcija = session.beginTransaction (); Proizvod proizvoda = novi proizvod (); product.setId (1); product.setName ("Proizvod 1"); session.save (proizvod); transakcija.commit (); } catch (Iznimka e) {rollbackTransactionQuietly (transakcija); baciti (e); } napokon {closeSessionQuietly (sesija); closeSessionFactoryQiietly (sessionFactory); }}

Neki drugi mogući uzroci su:

  • Korištena strategija imenovanja ne preslikava klase na ispravne tablice
  • Stupac naveden u @JoinColumn ne postoji

5.3. ConstraintViolationException

A ConstraintViolationException označava da je tražena DML operacija prouzročila kršenje ograničenja integriteta. Naziv ovog ograničenja možemo dobiti pozivom getConstraintName metoda.

Čest uzrok ove iznimke je pokušaj spremanja dvostrukih zapisa:

javna praznina whenDuplicateIdSaved_thenConstraintViolationException () {thrown.expect (isA (PersistenceException.class)); thrown.expectCause (isA (ConstraintViolationException.class)); thrown.expectMessage ("ConstraintViolationException: nije moguće izvršiti izraz"); Sjednica sesije = null; Transakcijska transakcija = null; for (int i = 1; i <= 2; i ++) {try {session = sessionFactory.openSession (); transakcija = session.beginTransaction (); Proizvod proizvoda = novi proizvod (); product.setId (1); product.setName ("Proizvod" + i); session.save (proizvod); transakcija.commit (); } catch (Iznimka e) {rollbackTransactionQuietly (transakcija); baciti (e); } napokon {closeSessionQuietly (sesija); }}}

Također, spremanje a null vrijednost prema a NIJE NULJA stupac u bazi podataka može dovesti do ove pogreške.

Da biste riješili ovu pogrešku, trebali bismo izvršiti sve provjere valjanosti na poslovnom sloju. Nadalje, ograničenja baze podataka ne bi se trebala koristiti za provjeru valjanosti aplikacija.

5.4. DataException

DataException označava da je procjena SQL izraza rezultirala nekom ilegalnom operacijom, neusklađenošću tipa ili netočnom kardinalnošću.

Na primjer, upotreba znakovnih podataka protiv numeričkog stupca može uzrokovati ovu pogrešku:

javna praznina givenQueryWithDataTypeMismatch_WhenQueryExecuted_thenDataException () {thrown.expectCause (isA (DataException.class)); thrown.expectMessage ("org.hibernate.exception.DataException: ne može pripremiti izjavu"); Sjednica sesije = sessionFactory.getCurrentSession (); NativeQuery query = session.createNativeQuery ("select * from PRODUCT where", Product.class); query.getResultList (); }

Da biste ispravili ovu pogrešku, trebali bismo osigurati da se vrste podataka i duljina podudaraju između aplikacijskog koda i baze podataka.

5.5. JDBCConnectionException

A JDBCConectionException ukazuje na probleme u komunikaciji s bazom podataka.

Na primjer, pad baze podataka ili mreže može uzrokovati bacanje ove iznimke.

Uz to, netočna postavka baze podataka može uzrokovati ovu iznimku. Jedan od takvih slučajeva je da je poslužitelj zatvorio vezu s bazom podataka jer je dugo bila neaktivna. To se može dogoditi ako koristimo spremanje veza i ako je postavka neaktivnog vremena čekanja na spremištu veća od vrijednosti vremenskog ograničenja veze u bazi podataka.

Da bismo riješili taj problem, prvo bismo trebali osigurati da je domaćin baze podataka prisutan i da je ustao. Zatim bismo trebali provjeriti koristi li se ispravna provjera autentičnosti za vezu baze podataka. Na kraju, trebali bismo provjeriti je li vrijednost vremenskog ograničenja ispravno postavljena na spremištu veza.

5.6. QueryTimeoutException

Kad upit baze podataka istekne, dobit ćemo ovu iznimku. Možemo ga vidjeti i zbog drugih pogrešaka, poput punjenja prostora tablica.

Ovo je jedna od rijetkih grešaka koje se mogu nadoknaditi, što znači da možemo pokušati izvod u istoj transakciji.

Da biste riješili ovaj problem, možemo povećati vremensko ograničenje upita za dugotrajne upite na više načina:

  • Postavi pauza element u a @NamedQuery ili @NamedNativeQuery bilješka
  • Prizovi setHint metoda upit sučelje
  • Nazovite setTimeout metoda Transakcija sučelje
  • Prizovi setTimeout metoda Upit sučelje

6. Pogreške povezane sa sesijom

Pogledajmo sada pogreške zbog pogrešaka korištenja sesije Hibernate.

6.1. NonUniqueObjectException

Hibernate ne dopušta dva objekta s istim identifikatorom u jednoj sesiji.

Ako pokušamo povezati dvije instance iste Java klase s istim identifikatorom u jednoj sesiji, dobit ćemo NonUniqueObjectException. Ime i identifikator entiteta možemo dobiti pozivom getEntityName () i getIdentifier () metode.

Da bismo reproducirali ovu pogrešku, pokušajmo spremiti dva primjerka Proizvod s istim id-om sa sesijom:

javna praznina givenSessionContainingAnId_whenIdAssociatedAgain_thenNonUniqueObjectException () {thrown.expect (isA (NonUniqueObjectException.class)); thrown.expectMessage ("Drugi se objekt s istom vrijednošću identifikatora već pridružio sesiji"); Sjednica sesije = null; Transakcijska transakcija = null; isprobajte {session = sessionFactory.openSession (); transakcija = session.beginTransaction (); Proizvod proizvoda = novi proizvod (); product.setId (1); product.setName ("Proizvod 1"); session.save (proizvod); proizvod = novi Proizvod (); product.setId (1); product.setName ("Proizvod 2"); session.save (proizvod); transakcija.commit (); } catch (Iznimka e) {rollbackTransactionQuietly (transakcija); baciti (e); } napokon {closeSessionQuietly (sesija); }}

Dobit ćemo NonUniqueObjectException, kako se očekivalo.

Ova se iznimka često događa tijekom ponovnog spajanja odvojenog objekta sa sesijom pozivanjem datoteke ažuriranje metoda. Ako sesija ima drugu instancu s učitanim istim identifikatorom, dobit ćemo ovu pogrešku. Da bi se to popravilo, možemo koristiti sjediniti metoda za ponovno pričvršćivanje odvojenog predmeta.

6.2. StaleStateException

Hibernate bacanja StaleStateExceptions kada provjera broja verzije ili vremenske oznake ne uspije. Označava da je sesija sadržavala zastarele podatke.

Ponekad se ovo zamota u OptimisticLockException.

Ova se pogreška obično događa tijekom korištenja dugotrajnih transakcija s verzijama.

Osim toga, može se dogoditi i prilikom pokušaja ažuriranja ili brisanja entiteta ako odgovarajući redak baze podataka ne postoji:

javna praznina whenUpdatingNonExistingObject_thenStaleStateException () {thrown.expect (isA (OptimisticLockException.class)); thrown.expectMessage ("Skupno ažuriranje vratilo je neočekivani broj redova iz ažuriranja"); thrown.expectCause (isA (StaleStateException.class)); Sjednica sesije = null; Transakcijska transakcija = null; isprobajte {session = sessionFactory.openSession (); transakcija = session.beginTransaction (); Proizvod proizvoda = novi proizvod (); product.setId (15); product.setName ("Product1"); session.update (proizvod); transakcija.commit (); } catch (Iznimka e) {rollbackTransactionQuietly (transakcija); baciti (e); } napokon {closeSessionQuietly (sesija); }}

Neki drugi mogući scenariji su:

  • nismo naveli odgovarajuću strategiju nespremljene vrijednosti za entitet
  • dva su korisnika pokušala izbrisati isti redak gotovo u isto vrijeme
  • ručno postavljamo vrijednost u polje automatski generiranog ID-a ili verzije

7. Pogreške lijene inicijalizacije

Obično konfiguriramo asocijacije koje se lijeno učitavaju kako bismo poboljšali izvedbu aplikacije. Asocijacije se dohvaćaju tek kad se prvi put koriste.

Međutim, Hibernate zahtijeva aktivnu sesiju za dohvaćanje podataka. Ako je sesija već zatvorena kada pokušavamo pristupiti neinicijaliziranoj udruzi, dobit ćemo iznimku.

Pogledajmo ovu iznimku i razne načine kako je popraviti.

7.1. LazyInitializationException

LazyInitializationException označava pokušaj učitavanja neinicijaliziranih podataka izvan aktivne sesije. Ovu pogrešku možemo dobiti u mnogim scenarijima.

Prvo, ovu iznimku možemo dobiti dok pristupamo lijenom odnosu u prezentacijskom sloju. Razlog je taj što je entitet djelomično učitan u poslovni sloj, a sesija je zatvorena.

Drugo, ovu pogrešku možemo dobiti s Spring Data ako koristimo uzmi jedan metoda. Ova metoda lijeno dohvaća instancu.

Postoji mnogo načina za rješavanje ove iznimke.

Prije svega, sve veze možemo učiniti željno opterećenima.Ali, to bi utjecalo na izvedbu aplikacije jer ćemo učitavati podatke koji se neće koristiti.

Kao drugo, možemo održavati sesiju otvorenom dok se prikaz ne generira. Ovo je poznato kao „Otvorena sesija u prikazu”I to je anti-obrazac. To bismo trebali izbjegavati jer ima nekoliko nedostataka.

Treće, možemo otvoriti drugu sesiju i ponovno spojiti entitet kako bismo dohvatili veze. To možemo učiniti pomoću sjediniti metoda na sesiji.

Napokon, možemo inicijalizirati potrebne asocijacije u poslovnim slojevima. O tome ćemo razgovarati u sljedećem odjeljku.

7.2. Inicijalizacija relevantnih lijenih odnosa na poslovnom sloju

Postoji mnogo načina za inicijalizaciju lijenih veza.

Jedna od mogućnosti je njihova inicijalizacija pozivanjem odgovarajućih metoda na entitetu. U ovom će slučaju Hibernate izdati više upita baze podataka koji uzrokuju pogoršane performanse. To nazivamo problemom "N + 1 SELECT".

Drugo, možemo koristiti Dohvati Pridružite se za dobivanje podataka u jednom upitu. Međutim, moramo napisati prilagođeni kôd da bismo to postigli.

Konačno, možemo koristiti grafikone entiteta za definiranje svih atributa koji se preuzimaju. Možemo se poslužiti bilješkama @NamedEntityGraph, @NamedAttributeNode, i @NamedEntitySubgraph da deklarativno definira graf entiteta. Također ih možemo programski definirati pomoću JPA API-ja. Zatim, dohvaćamo cijeli graf u jednom pozivu tako što ga specificiramo u operaciji dohvaćanja.

8. Pitanja o transakcijama

Transakcije definiraju jedinice rada i izolaciju između istodobnih aktivnosti. Možemo ih razgraničiti na dva različita načina. Prvo, možemo ih deklarativno definirati pomoću bilješki. Drugo, njima možemo programski upravljati pomoću Hibernate Transaction API.

Nadalje, Hibernate delegira upravljanje transakcijama upravitelju transakcija. Ako se transakcija iz bilo kojeg razloga nije mogla pokrenuti, počiniti ili vratiti, Hibernate donosi iznimku.

Obično dobijemo a TransactionException ili an IlegalArgumentException ovisno o voditelju transakcija.

Kao ilustraciju, pokušajmo izvršiti transakciju koja je označena za vraćanje:

javna praznina givenTxnMarkedRollbackOnly_whenCommitted_thenTransactionException () {thrown.expect (isA (TransactionException.class)); thrown.expectMessage ("Transakcija je označena samo za povrat, ne može se izvršiti"); Sjednica sesije = null; Transakcijska transakcija = null; isprobajte {session = sessionFactory.openSession (); transakcija = session.beginTransaction (); Proizvod proizvoda = novi proizvod (); product.setId (15); product.setName ("Product1"); session.save (proizvod); action.setRollbackOnly (); transakcija.commit (); } catch (Iznimka e) {rollbackTransactionQuietly (transakcija); baciti (e); } napokon {closeSessionQuietly (sesija); }}

Slično tome, i druge pogreške mogu uzrokovati iznimku:

  • Miješanje deklarativnih i programskih transakcija
  • Pokušaj pokretanja transakcije kada je druga već aktivna u sesiji
  • Pokušaj predavanja ili vraćanja bez pokretanja transakcije
  • Pokušaj izvršavanja ili vraćanja transakcije više puta

9. Pitanja o istodobnosti

Hibernate podržava dvije strategije zaključavanja kako bi se spriječila nedosljednost baze podataka zbog istodobnih transakcija - optimistična i pesimistična. Oboje iznose iznimku u slučaju sukoba zaključavanja.

Da bismo podržali visoku istodobnost i veliku skalabilnost, obično koristimo optimističnu kontrolu paralelnosti s provjerom verzija. Ovo koristi brojeve verzija ili vremenske oznake za otkrivanje sukobljenih ažuriranja.

OptimisticLockingException baca se da ukaže na optimističan sukob zaključavanja. Na primjer, ovu pogrešku dobivamo ako izvršimo dva ažuriranja ili brisanja istog entiteta bez osvježavanja nakon prve operacije:

javna praznina whenDeletingADeletedObject_thenOptimisticLockException () {thrown.expect (isA (OptimisticLockException.class)); thrown.expectMessage ("Skupno ažuriranje vratilo je neočekivani broj redova iz ažuriranja"); thrown.expectCause (isA (StaleStateException.class)); Sjednica sesije = null; Transakcijska transakcija = null; isprobajte {session = sessionFactory.openSession (); transakcija = session.beginTransaction (); Proizvod proizvoda = novi proizvod (); product.setId (12); product.setName ("Proizvod 12"); session.save (proizvod1); transakcija.commit (); session.close (); session = sessionFactory.openSession (); transakcija = session.beginTransaction (); product = session.get (Product.class, 12); session.createNativeQuery ("izbriši iz proizvoda gdje je id = 12") .executeUpdate (); // Moramo se osvježiti da bismo ispravili pogrešku. // session.refresh (proizvod); session.delete (proizvod); transakcija.commit (); } catch (Iznimka e) {rollbackTransactionQuietly (transakcija); baciti (e); } napokon {closeSessionQuietly (sesija); }}

Isto tako, ovu pogrešku možemo dobiti i ako dva korisnika pokušaju ažurirati isti entitet gotovo u isto vrijeme. U ovom slučaju, prvi može uspjeti, a drugi pokreće ovu pogrešku.

Stoga, ovu pogrešku ne možemo u potpunosti izbjeći bez uvođenja pesimističnog zaključavanja. Međutim, vjerojatnost njegovog nastanka možemo umanjiti na sljedeći način:

  • Neka operacije ažuriranja budu što kraće
  • Ažurirajte prikaze entiteta u klijentu što je češće moguće
  • Nemojte predmemorirati entitet ili bilo koji objekt vrijednosti koji ga predstavlja
  • Uvijek osvježite predstavljanje entiteta na klijentu nakon ažuriranja

10. Zaključak

U ovom smo članku proučili neke uobičajene iznimke kod kojih je došlo do upotrebe hibernacije. Nadalje, istražili smo njihove vjerojatne uzroke i rješenja.

Kao i obično, puni izvorni kod možete pronaći na GitHubu.