Almindelige dvaleundtagelser

1. Introduktion

I denne vejledning diskuterer vi nogle almindelige undtagelser, vi kan støde på, mens vi arbejder med dvale.

Vi gennemgår deres formål og nogle almindelige årsager. Derudover vil vi se på deres løsninger.

2. Oversigt over dvaleundtagelse

Mange forhold kan medføre undtagelser, når du bruger dvale. Disse kan være kortlægningsfejl, infrastrukturproblemer, SQL-fejl, dataintegritetsovertrædelser, sessionsproblemer og transaktionsfejl.

Disse undtagelser strækker sig for det meste fra HibernateException. Men hvis vi bruger dvale som en JPA-persistensudbyder, kan disse undtagelser blive pakket ind i PersistenceException.

Begge disse basisklasser strækker sig fra RuntimeException. Derfor er de alle ukontrollerede. Derfor behøver vi ikke fange eller erklære dem overalt, hvor de er brugt.

Desuden, de fleste af disse er uoprettelige. Som et resultat, ville det ikke hjælpe igen at prøve operationen. Dette betyder, at vi er nødt til at opgive den nuværende session, når vi møder dem.

Lad os nu se på hver af disse, en ad gangen.

3. Kortlægningsfejl

Objektrelationskortlægning er en stor fordel ved dvale. Specifikt frigør det os fra manuelt at skrive SQL-udsagn.

Samtidig kræver det, at vi specificerer kortlægningen mellem Java-objekter og databasetabeller. Derfor specificerer vi dem ved hjælp af kommentarer eller gennem kortlægning af dokumenter. Disse tilknytninger kan kodes manuelt. Alternativt kan vi bruge værktøjer til at generere dem.

Mens vi specificerer disse kortlægninger, kan vi begå fejl. Disse kan være i kortlægningsspecifikationen. Eller der kan være en uoverensstemmelse mellem et Java-objekt og den tilsvarende databasetabel.

Sådanne kortlægningsfejl genererer undtagelser. Vi støder ofte på dem under den første udvikling. Derudover kan vi støde på dem, mens vi migrerer ændringer på tværs af miljøer.

Lad os se på disse fejl med nogle eksempler.

3.1. MappingException

Et problem med objektrelationskortlægningen forårsager a MappingException at blive kastet:

offentligt ugyldigt nårQueryExecutedWithUnmappedEntity_thenMappingException () {throw.expectCause (isA (MappingException.class)); throw.expectMessage ("Ukendt enhed: java.lang.String"); Session session = sessionFactory.getCurrentSession (); NativeQuery-forespørgsel = session .createNativeQuery ("vælg navn fra PRODUKT", String.class); query.getResultList (); }

I ovenstående kode er createNativeQuery metode forsøger at kortlægge forespørgselsresultatet til den angivne Java-type Snor. Det bruger den implicitte kortlægning af Snor klasse fra Metamodel at foretage kortlægningen.

Men den Snor klasse har ikke angivet nogen kortlægning. Derfor ved dvale ikke, hvordan man kortlægger navn kolonne til Snor og kaster undtagelsen.

Hvis du vil have en detaljeret analyse af mulige årsager og løsninger, skal du tjekke undtagelsen Hibernate Mapping - Unknown Entity.

Tilsvarende kan andre fejl også forårsage denne undtagelse:

  • Blanding af bemærkninger om felter og metoder
  • Kunne ikke specificere @JoinTable til en @ManyToMany forening
  • Standardkonstruktøren for den kortlagte klasse kaster en undtagelse under kortlægningsprocessen

Desuden, MappingException har et par underklasser, der kan indikere specifikke kortlægningsproblemer:

  • AnnotationException - et problem med en kommentar
  • DuplicateMappingException - duplikatkortlægning for et klasse-, tabel- eller ejendomsnavn
  • InvalidMappingException - kortlægning er ugyldig
  • MappingNotFoundException - kortlægningsressource kunne ikke findes
  • PropertyNotFoundException - en forventet getter eller setter metode kunne ikke findes på en klasse

Derfor, hvis vi støder på denne undtagelse, skal vi først kontrollere vores kortlægninger.

3.2. Annotation Exception

At forstå Annotation Exception, lad os oprette en enhed uden en identifikator-kommentar på noget felt eller ejendom:

@Entity offentlig klasse EntityWithNoId {privat int id; public int getId () {return id; } // standard sætter}

Siden Dvaletilstand forventer, at enhver enhed har en identifikator, vi får en Annotation Exception når vi bruger enheden:

offentlig ugyldighed givenEntityWithoutId_whenSessionFactoryCreated_thenAnnotationException () {throw.expect (AnnotationException.class); throw.expectMessage ("Ingen identifikator angivet for enhed"); Konfiguration cfg = getConfiguration (); cfg.addAnnotatedClass (EntityWithNoId.class); cfg.buildSessionFactory (); }

Desuden er nogle andre sandsynlige årsager:

  • Ukendt sekvensgenerator brugt i @GeneratedValue kommentar
  • @Temporal kommentar brugt med en Java 8 Dato/Tid klasse
  • Målenhed mangler eller ikke eksisterer for @ManyToOne eller @OneToMany
  • Rå indsamlingsklasser brugt med forholdsbemærkninger @OneToMany eller @ManyToMany
  • Betonklasser, der bruges med samlingens annoteringer @OneToMany, @ManyToMany eller @ElementCollection som dvale forventer samlingsgrænsefladerne

For at løse denne undtagelse skal vi først kontrollere den specifikke kommentar, der er nævnt i fejlmeddelelsen.

4. Fejl ved skemastyring

Automatisk databaseskemaadministration er en anden fordel ved dvale. For eksempel kan det generere DDL-udsagn for at oprette eller validere databaseobjekter.

For at bruge denne funktion skal vi indstille dvale.hbm2ddl.auto ejendom korrekt.

Hvis der er problemer under udførelse af skemastyring, får vi en undtagelse. Lad os undersøge disse fejl.

4.1. SchemaManagementException

Ethvert infrastrukturrelateret problem ved udførelse af skemastyring forårsager en SchemaManagementException.

Lad os instruere dvale om at validere databaseskemaet for at demonstrere:

offentlig ugyldighed givenMissingTable_whenSchemaValidated_thenSchemaManagementException () {throw.expect (SchemaManagementException.class); throw.expectMessage ("Skema-validering: manglende tabel"); Konfiguration cfg = getConfiguration (); cfg.setProperty (AvailableSettings.HBM2DDL_AUTO, "validere"); cfg.addAnnotatedClass (Product.class); cfg.buildSessionFactory (); }

Da tabellen svarer til Produkt ikke er til stede i databasen, får vi skemavalideringsundtagelsen, mens vi bygger SessionFactory.

Derudover er der andre mulige scenarier for denne undtagelse:

  • ikke i stand til at oprette forbindelse til databasen for at udføre skemaadministrationsopgaver
  • skemaet findes ikke i databasen

4.2. CommandAcceptanceException

Ethvert problem med at udføre en DDL, der svarer til en bestemt skemastyringskommando, kan forårsage CommandAcceptanceException.

Lad os som et eksempel angive den forkerte dialekt, mens vi konfigurerer SessionFactory:

offentligt ugyldigt når WrongDialectSpecified_thenCommandAcceptanceException () {throw.expect (SchemaManagementException.class); throw.expectCause (isA (CommandAcceptanceException.class)); throw.expectMessage ("Stop ved fejl: Fejl ved udførelse af DDL"); Konfiguration cfg = getConfiguration (); cfg.setProperty (AvailableSettings.DIALECT, "org.hibernate.dialect.MySQLDialect"); cfg.setProperty (AvailableSettings.HBM2DDL_AUTO, "opdatering"); cfg.setProperty (AvailableSettings.HBM2DDL_HALT_ON_ERROR, "sand"); cfg.getProperties () .put (AvailableSettings.HBM2DDL_HALT_ON_ERROR, sandt); cfg.addAnnotatedClass (Product.class); cfg.buildSessionFactory (); }

Her har vi angivet den forkerte dialekt: MySQLDialect. Vi instruerer også i dvale om at opdatere skemaobjekterne. Derfor mislykkes DDL-udsagnene, der udføres af Hibernate for at opdatere H2-databasen, og vi får en undtagelse.

Som standard logger Dvale stille denne undtagelse stille og fortsætter. Når vi senere bruger SessionFabrik, vi får undtagelsen.

For at sikre, at der er en undtagelse for denne fejl, har vi indstillet ejendommen HBM2DDL_HALT_ON_ERROR til rigtigt.

Tilsvarende er dette nogle andre almindelige årsager til denne fejl:

  • Der er en uoverensstemmelse i kolonnenavne mellem kortlægning og databasen
  • To klasser kortlægges til samme tabel
  • Navnet, der bruges til en klasse eller tabel, er et reserveret ord i databasen, ligesom BRUGER, for eksempel
  • Den bruger, der bruges til at oprette forbindelse til databasen, har ikke det nødvendige privilegium

5. SQL-udførelsesfejl

Når vi indsætter, opdaterer, sletter eller forespørger om data ved hjælp af dvale, udfører det DML-udsagn mod databasen ved hjælp af JDBC. Denne API rejser en SQLException hvis operationen resulterer i fejl eller advarsler.

Dvaletilstand konverterer denne undtagelse til JDBCE undtagelse eller en af ​​dens egnede underklasser:

  • ConstraintViolationException
  • DataException
  • JDBCConnectionException
  • LockAcquisitionException
  • PessimistiskLåseundtagelse
  • QueryTimeoutException
  • SQLGrammarException
  • GeneriskJDBCException

Lad os diskutere almindelige fejl.

5.1. JDBCE undtagelse

JDBCE undtagelse skyldes altid en bestemt SQL-sætning. Vi kan ringe til getSQL metode til at få den fornærmende SQL-sætning.

Desuden kan vi hente det underliggende SQLException med getSQLException metode.

5.2. SQLGrammarException

SQLGrammarException angiver, at SQL sendt til databasen var ugyldig. Det kan skyldes en syntaksfejl eller en ugyldig objektreference.

For eksempel, en manglende tabel kan resultere i denne fejl under forespørgsel på data:

offentlig ugyldighed givenMissingTable_whenQueryExecuted_thenSQLGrammarException () {throw.expect (isA (PersistenceException.class)); throw.expectCause (isA (SQLGrammarException.class)); throw.expectMessage ("SQLGrammarException: kunne ikke forberede udsagn"); Session session = sessionFactory.getCurrentSession (); NativeQuery forespørgsel = session.createNativeQuery ("vælg * fra NON_EXISTING_TABLE", Product.class); query.getResultList (); }

Vi kan også få denne fejl, mens vi gemmer data, hvis tabellen mangler:

offentlig ugyldighed givenMissingTable_whenEntitySaved_thenSQLGrammarException () {throw.expect (isA (PersistenceException.class)); throw.expectCause (isA (SQLGrammarException.class)); kastet .expectMessage ("SQLGrammarException: kunne ikke forberede udsagn"); Konfiguration cfg = getConfiguration (); cfg.addAnnotatedClass (Product.class); SessionFactory sessionFactory = cfg.buildSessionFactory (); Sessionssession = null; Transaktionstransaktion = null; prøv {session = sessionFactory.openSession (); transaktion = session.beginTransaction (); Produkt produkt = nyt produkt (); product.setId (1); product.setName ("Produkt 1"); session.save (produkt); transaktion.forpligtelse (); } fange (Undtagelse e) {rollbackTransactionQuietly (transaktion); kast (e); } endelig {closeSessionQuietly (session); closeSessionFactoryQuietly (sessionFactory); }}

Nogle andre mulige årsager er:

  • Den anvendte navngivningsstrategi kortlægger ikke klasserne til de korrekte tabeller
  • Kolonnen angivet i @JoinColumn eksisterer ikke

5.3. ConstraintViolationException

EN ConstraintViolationException angiver, at den anmodede DML-handling medførte, at en integritetsbegrænsning blev overtrådt. Vi kan få navnet på denne begrænsning ved at kalde getConstraintName metode.

En almindelig årsag til denne undtagelse er at forsøge at gemme duplikatposter:

offentlig tomrum nårDuplicateIdSaved_thenConstraintViolationException () {throw.expect (isA (PersistenceException.class)); throw.expectCause (isA (ConstraintViolationException.class)); throw.expectMessage ("ConstraintViolationException: kunne ikke udføre erklæring"); Sessionssession = null; Transaktionstransaktion = null; for (int i = 1; i <= 2; i ++) {prøv {session = sessionFactory.openSession (); transaktion = session.beginTransaction (); Produkt produkt = nyt produkt (); product.setId (1); product.setName ("Produkt" + i); session.save (produkt); transaktion.forpligtelse (); } fange (Undtagelse e) {rollbackTransactionQuietly (transaktion); kast (e); } endelig {closeSessionQuietly (session); }}}

Også at gemme en nul værdi til en IKKE NULL kolonne i databasen kan rejse denne fejl.

For at løse denne fejl, vi skal udføre alle valideringer i forretningslaget. Desuden bør databasebegrænsninger ikke bruges til at foretage applikationsvalidering.

5.4. DataException

DataException indikerer, at evalueringen af ​​en SQL-sætning resulterede i en vis ulovlig handling, typefejl eller forkert kardinalitet.

For eksempel kan brug af tegndata i en numerisk kolonne forårsage denne fejl:

offentlig ugyldighed givenQueryWithDataTypeMismatch_WhenQueryExecuted_thenDataException () {throw.expectCause (isA (DataException.class)); throw.expectMessage ("org.hibernate.exception.DataException: kunne ikke forberede udsagn"); Session session = sessionFactory.getCurrentSession (); NativeQuery-forespørgsel = session.createNativeQuery ("vælg * fra PRODUCT hvor", Product.class); query.getResultList (); }

For at rette denne fejl, vi skal sikre, at datatyperne og længden stemmer overens med applikationskoden og databasen.

5.5. JDBCConnectionException

EN JDBCConectionException angiver problemer med at kommunikere med databasen.

For eksempel kan en database eller et netværk, der går ned, få denne undtagelse til at blive kastet.

Derudover kan en forkert databaseopsætning forårsage denne undtagelse. Et sådant tilfælde er, at databaseforbindelsen lukkes af serveren, fordi den har været inaktiv i lang tid. Dette kan ske, hvis vi bruger forbindelsespooling, og indstillingen for inaktiv timeout på puljen er mere end forbindelses timeoutværdien i databasen.

For at løse dette problem skal vi først sikre os, at databasehost er til stede, og at den er op. Derefter skal vi kontrollere, at den korrekte godkendelse bruges til databaseforbindelsen. Endelig skal vi kontrollere, at timeoutværdien er korrekt indstillet på forbindelsespoolen.

5.6. QueryTimeoutException

Når en databaseforespørgsel timeout, får vi denne undtagelse. Vi kan også se det på grund af andre fejl, såsom at tabellen bliver fuld.

Dette er en af ​​de få gendannelsesfejl, hvilket betyder, at vi kan prøve erklæringen igen i den samme transaktion.

For at løse dette problem, vi kan øge timeout for forespørgsler for langvarige forespørgsler på flere måder:

  • Indstil tiden er gået element i en @NamedQuery eller @NamedNativeQuery kommentar
  • Påkald setHint metode til forespørgslen interface
  • Ring til setTimeout metode til Transaktion interface
  • Påkald setTimeout metode til Forespørgsel interface

6. Sessions-statsrelaterede fejl

Lad os nu se på fejl på grund af dvaletilstandsforbrugsfejl.

6.1. NonUniqueObjectException

Dvaletilstand tillader ikke to objekter med samme identifikator i en enkelt session.

Hvis vi forsøger at knytte to forekomster af den samme Java-klasse til den samme identifikator i en enkelt session, får vi en NonUniqueObjectException. Vi kan få enhedens navn og identifikator ved at ringe til getEntityName () og getIdentifier () metoder.

Lad os prøve at gemme to forekomster af for at reproducere denne fejl Produkt med samme id med en session:

offentlig ugyldighed givenSessionContainingAnId_whenIdAssociatedAgain_thenNonUniqueObjectException () {throw.expect (isA (NonUniqueObjectException.class)); throw.expectMessage ("Et andet objekt med samme identifikationsværdi var allerede forbundet med sessionen"); Sessionssession = null; Transaktionstransaktion = null; prøv {session = sessionFactory.openSession (); transaktion = session.beginTransaction (); Produkt produkt = nyt produkt (); product.setId (1); product.setName ("Produkt 1"); session.save (produkt); produkt = nyt produkt (); product.setId (1); product.setName ("Produkt 2"); session.save (produkt); transaktion.forpligtelse (); } fange (Undtagelse e) {rollbackTransactionQuietly (transaktion); kast (e); } endelig {closeSessionQuietly (session); }}

Vi får en NonUniqueObjectException, som forventet.

Denne undtagelse forekommer ofte, når et fritliggende objekt genoprettes med en session ved at ringe til opdatering metode. Hvis sessionen har en anden forekomst med samme identifikator indlæst, får vi denne fejl. For at løse dette, vi kan bruge fusionere metode for at fastgøre det løsrevne objekt igen.

6.2. StaleStateException

Dvale kaster StaleStateExceptions når versionsnummeret eller tidsstempelkontrollen mislykkes. Det indikerer, at sessionen indeholdt uaktuelle data.

Nogle gange bliver dette pakket ind i en OptimisticLockException.

Denne fejl sker normalt, når du bruger langvarige transaktioner med versionering.

Derudover kan det også ske, mens du prøver at opdatere eller slette en enhed, hvis den tilsvarende databaserække ikke findes:

offentlig ugyldighed nårUpdatingNonExistingObject_thenStaleStateException () {throw.expect (isA (OptimisticLockException.class)); throw.expectMessage ("Batchopdatering returnerede uventet rækkeantal fra opdatering"); throw.expectCause (isA (StaleStateException.class)); Sessionssession = null; Transaktionstransaktion = null; prøv {session = sessionFactory.openSession (); transaktion = session.beginTransaction (); Produkt produkt = nyt produkt (); product.setId (15); product.setName ("Product1"); session.update (produkt); transaktion.forpligtelse (); } fange (Undtagelse e) {rollbackTransactionQuietly (transaktion); kaste (e); } endelig {closeSessionQuietly (session); }}

Nogle andre mulige scenarier er:

  • Vi specificerede ikke en korrekt strategi for ikke-gemt værdi for enheden
  • to brugere forsøgte at slette den samme række næsten på samme tid
  • vi indstiller manuelt en værdi i det autogenererede ID eller versionsfelt

7. Lazy initialiseringsfejl

Vi konfigurerer normalt foreninger, der skal indlæses dovent for at forbedre applikationsydelsen. Foreningerne hentes kun, når de først bruges.

Dvale kræver dog en aktiv session for at hente data. Hvis sessionen allerede er lukket, når vi prøver at få adgang til en ikke-initialiseret tilknytning, får vi en undtagelse.

Lad os se på denne undtagelse og de forskellige måder at rette den på.

7.1. LazyInitializationException

LazyInitializationException angiver et forsøg på at indlæse ikke-initialiserede data uden for en aktiv session. Vi kan få denne fejl i mange scenarier.

For det første kan vi få denne undtagelse, når vi får adgang til et dovent forhold i præsentationslaget. Årsagen er, at enheden delvist blev indlæst i forretningslaget, og sessionen blev lukket.

For det andet kan vi få denne fejl med Spring Data, hvis vi bruger få en metode. Denne metode henter den instans doven.

Der er mange måder at løse denne undtagelse på.

Først og fremmest kan vi gøre alle forhold ivrigt belastede.Men dette vil påvirke applikationens ydeevne, fordi vi indlæser data, der ikke bruges.

For det andet kan vi holde sessionen åben, indtil visningen gengives. Dette er kendt som “Åbn session i visning”Og det er et antimønster. Vi bør undgå dette, da det har flere ulemper.

For det tredje kan vi åbne en anden session og tilslutte enheden igen for at hente forholdene. Det kan vi gøre ved at bruge fusionere metode på sessionen.

Endelig kan vi initialisere de krævede tilknytninger i forretningslagene. Vi diskuterer dette i det næste afsnit.

7.2. Initialisering af relevante dovne forhold i forretningslaget

Der er mange måder at initialisere dovne forhold på.

En mulighed er at initialisere dem ved at påkalde de tilsvarende metoder på enheden. I dette tilfælde udsender Hibernate flere databaseforespørgsler, der forårsager forringet ydeevne. Vi henviser til det som “N + 1 SELECT” -problemet.

For det andet kan vi bruge Hent Join for at få dataene i en enkelt forespørgsel. Vi skal dog skrive tilpasset kode for at opnå dette.

Langt om længe, vi kan bruge enhedsgrafer til at definere alle attributter, der skal hentes. Vi kan bruge kommentarerne @NamedEntityGraph, @NamedAttributeNodeog @NamedEntitySubgraph at erklærende definere enhedsgrafen. Vi kan også definere dem programmatisk med JPA API. Derefter, vi henter hele grafen i et enkelt opkald ved at specificere det i hentningsoperationen.

8. Transaktionsproblemer

Transaktioner definerer arbejdsenheder og isolering mellem samtidige aktiviteter. Vi kan afgrænse dem på to forskellige måder. For det første kan vi definere dem erklærende ved hjælp af annoteringer. For det andet kan vi administrere dem programmatisk ved hjælp af Hibernate Transaction API.

Desuden delegerer Hibernate transaktionsstyringen til en transaktionsmanager. Hvis en transaktion af en eller anden grund ikke kunne startes, begås eller rulles tilbage, kaster dvale en undtagelse.

Vi får normalt en TransactionException eller en IllegalArgumentException afhængigt af transaktionschefen.

Lad os som en illustration prøve at begå en transaktion, der er markeret for tilbageførsel:

offentlig ugyldighed givenTxnMarkedRollbackOnly_whenCommitted_thenTransactionException () {throw.expect (isA (TransactionException.class)); throw.expectMessage ("Transaktion var kun markeret for tilbageførsel; kan ikke begå"); Sessionssession = null; Transaktionstransaktion = null; prøv {session = sessionFactory.openSession (); transaktion = session.beginTransaction (); Produkt produkt = nyt produkt (); product.setId (15); product.setName ("Product1"); session.save (produkt); transaction.setRollbackOnly (); transaktion.forpligtelse (); } fange (Undtagelse e) {rollbackTransactionQuietly (transaktion); kaste (e); } endelig {closeSessionQuietly (session); }}

Tilsvarende kan andre fejl også forårsage en undtagelse:

  • Blanding af deklarative og programmatiske transaktioner
  • Forsøger at starte en transaktion, når en anden allerede er aktiv i sessionen
  • Forsøger at begå eller tilbageføre uden at starte en transaktion
  • Forsøger at begå eller tilbageføre en transaktion flere gange

9. Samtidige problemer

Dvaletilstand understøtter to låsestrategier for at forhindre inkonsekvens i databaser på grund af samtidige transaktioner - optimistisk og pessimistisk. Begge to gør en undtagelse i tilfælde af en låsende konflikt.

For at understøtte høj samtidighed og høj skalerbarhed bruger vi typisk optimistisk samtidighedskontrol med versionskontrol. Dette bruger versionsnumre eller tidsstempler til at opdage modstridende opdateringer.

OptimistiskLåseundtagelse kastes for at indikere en optimistisk låsekonflikt. For eksempel får vi denne fejl, hvis vi udfører to opdateringer eller sletninger af den samme enhed uden at opdatere den efter den første operation:

offentlig ugyldighed nårDeletingADeletedObject_thenOptimisticLockException () {throw.expect (isA (OptimisticLockException.class)); throw.expectMessage ("Batchopdatering returnerede uventet rækkeantal fra opdatering"); throw.expectCause (isA (StaleStateException.class)); Sessionssession = null; Transaktionstransaktion = null; prøv {session = sessionFactory.openSession (); transaktion = session.beginTransaction (); Produkt produkt = nyt produkt (); product.setId (12); product.setName ("Produkt 12"); session.save (produkt1); transaktion.forpligtelse (); session.close (); session = sessionFactory.openSession (); transaktion = session.beginTransaction (); produkt = session.get (Product.class, 12); session.createNativeQuery ("slet fra produkt hvor id = 12") .executeUpdate (); // Vi skal opdatere for at rette fejlen. // session.refresh (produkt); session.delete (produkt); transaktion.forpligtelse (); } fange (Undtagelse e) {rollbackTransactionQuietly (transaktion); kaste (e); } endelig {closeSessionQuietly (session); }}

På samme måde kan vi også få denne fejl, hvis to brugere forsøger at opdatere den samme enhed næsten på samme tid. I dette tilfælde kan det første lykkes, og det andet rejser denne fejl.

Derfor, vi kan ikke helt undgå denne fejl uden at indføre pessimistisk låsning. Vi kan dog minimere sandsynligheden for dens forekomst ved at gøre følgende:

  • Hold opdateringshandlinger så korte som muligt
  • Opdater enhedsrepræsentationer i klienten så ofte som muligt
  • Cache ikke enheden eller noget værdiobjekt, der repræsenterer den, i cache
  • Opdater altid enhedens repræsentation på klienten efter opdatering

10. Konklusion

I denne artikel kiggede vi på nogle almindelige undtagelser, der blev fundet under brug af dvale. Desuden undersøgte vi deres sandsynlige årsager og beslutninger.

Som sædvanlig kan den fulde kildekode findes på GitHub.