Programmering

Kom godt i gang med dvale

Det er godt at forstå behovet for objekt- / relationskortlægning (ORM) i Java-applikationer, men du er sandsynligvis ivrig efter at se dvale i aktion. Vi starter med at vise dig et simpelt eksempel, der viser noget af dets magt.

Som du sikkert ved, er det traditionelt, at en programmeringsbog starter med et "Hello World" -eksempel. I dette kapitel følger vi denne tradition ved at introducere dvale med et relativt simpelt "Hello World" -program. Imidlertid er det simpelthen ikke nok at udskrive en besked til et konsolvindue til virkelig at demonstrere dvale. I stedet gemmer vores program nyoprettede objekter i databasen, opdaterer dem og udfører forespørgsler for at hente dem fra databasen.

Ud over det kanoniske "Hello World" -eksempel introducerer vi de centrale dvale-API'er og giver detaljer for en grundlæggende konfiguration.

"Hej verden" med dvale

Dvale-applikationer definerer vedvarende klasser, der "kortlægges" til databasetabeller. Vores "Hello World" -eksempel består af en klasse og en kortfil. Lad os se, hvordan en simpel vedvarende klasse ser ud, hvordan kortlægningen er specificeret, og nogle af de ting, vi kan gøre med forekomster af den vedvarende klasse, der bruger dvale.

Målet med vores prøveapplikation er at gemme meddelelser i en database og hente dem til visning. Applikationen har en simpel vedvarende klasse, Besked, som repræsenterer disse udskrivbare meddelelser. Vores Besked klasse vises i liste 1.

Liste 1. Message.java: En simpel vedvarende klasse

pakke hej; offentlig klasse Besked {privat Lang id; privat strengtekst; privat besked nextMessage; privat besked () {} offentlig besked (strengtekst) {denne.tekst = tekst; } offentlig Lang getId () {return id; } privat ugyldigt setId (langt id) {this.id = id; } offentlig String getText () {returtekst; } public void setText (String text) {this.text = text; } offentlig besked getNextMessage () {return nextMessage; } public void setNextMessage (Message nextMessage) {this.nextMessage = nextMessage; }} 

Vores Besked klasse har tre attributter: identifikationsattributten, meddelelsens tekst og en henvisning til en anden Besked. Identifikationsattributten giver applikationen adgang til databaseidentiteten - den primære nøgleværdi - for et vedvarende objekt. Hvis to tilfælde af Besked har den samme identifikationsværdi, de repræsenterer den samme række i databasen. Vi har valgt Lang for typen af ​​vores identifikationsattribut, men dette er ikke et krav. Dvaletilstand tillader stort set alt for identifikationstypen, som du vil se senere.

Du har måske bemærket, at alle attributter til Besked klasse har JavaBean-stil ejendomsadgangsmetoder. Klassen har også en konstruktør uden parametre. De vedvarende klasser, vi bruger i vores eksempler, vil næsten altid se sådan ud.

Forekomster af Besked klasse styres muligvis (gøres vedholdende) af dvale, men det gør de ikke har at være. Siden Besked objekt implementerer ingen dvale-specifikke klasser eller grænseflader, vi kan bruge det som enhver anden Java-klasse:

Beskedbesked = ny besked ("Hello World"); System.out.println (message.getText ()); 

Dette kodefragment gør præcis, hvad vi forventer af "Hello World" -applikationer: Det udskrives "Hej Verden" til konsollen. Det kan se ud som om vi prøver at være søde her; faktisk demonstrerer vi en vigtig funktion, der adskiller dvale fra nogle andre persistensløsninger, såsom EJB (Enterprise JavaBean) enhedsbønner. Vores vedvarende klasse kan bruges i enhver eksekveringssammenhæng - der kræves ingen speciel container. Selvfølgelig kom du her for at se Hibernate selv, så lad os gemme et nyt Besked til databasen:

Session session = getSessionFactory (). OpenSession (); Transaktion tx = session.beginTransaction (); Beskedbesked = ny besked ("Hello World"); session.save (besked); tx.commit (); session.close (); 

Denne kode kalder dvale Session og Transaktion grænseflader. (Vi kommer til det getSessionFactory () ring hurtigt.) Det resulterer i udførelse af noget, der ligner følgende SQL:

indsæt i MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID) værdier (1, 'Hello World', null) 

Vent - den MESSAGE_ID kolonnen initialiseres til en underlig værdi. Vi indstillede ikke id ejendom af besked hvor som helst, så vi ville forvente, at det var nul, ret? Faktisk id ejendom er speciel: Det er en identifikatoregenskab—Det har en genereret unik værdi. (Vi diskuterer, hvordan værdien genereres senere.) Værdien tildeles til Besked eksempel ved dvale når Gemme() Hedder.

I dette eksempel antager vi, at BESKEDER tabellen findes allerede. Naturligvis ønsker vi, at vores "Hello World" -program udskriver beskeden til konsollen. Nu hvor vi har en besked i databasen, er vi klar til at demonstrere dette. Det næste eksempel henter alle meddelelser fra databasen i alfabetisk rækkefølge og udskriver dem:

Session newSession = getSessionFactory (). OpenSession (); Transaktion newTransaction = newSession.beginTransaction (); Vis meddelelser = newSession.find ("fra Besked som m rækkefølge efter m.text asc"); System.out.println (meddelelser.størrelse () + "meddelelse (r) fundet:"); for (Iterator iter = messages.iterator (); iter.hasNext ();) {Message message = (Message) iter.next (); System.out.println (message.getText ()); } newTransaction.commit (); newSession.close (); 

Den bogstavelige streng "fra besked som m rækkefølge efter m.text asc" er en dvale-forespørgsel, udtrykt i Hibernates eget objektorienterede Hibernate Query Language (HQL). Denne forespørgsel oversættes internt til følgende SQL, når finde() Hedder:

vælg m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID fra MESSAGES m rækkefølge efter m.MESSAGE_TEXT asc 

Kodefragmentet udskrives:

1 meddelelse fundet: Hello World 

Hvis du aldrig har brugt et ORM-værktøj som Hibernate før, forventede du sandsynligvis at se SQL-sætningerne et eller andet sted i koden eller metadataene. De er ikke der. Al SQL genereres ved kørsel (faktisk ved opstart for alle genanvendelige SQL-sætninger).

For at lade denne magi opstå, har dvale brug for mere information om, hvordan Besked klasse skal gøres vedholdende. Disse oplysninger gives normalt i en XML-kortlægningsdokument. Kortlægningsdokumentet definerer blandt andet, hvordan egenskaber for Besked klassekort til kolonner i BESKEDER bord. Lad os se på kortlægningsdokumentet i Listing 2.

Liste 2. En simpel dvale-XML-kortlægning

Kortlægningsdokumentet fortæller dvale, at Besked klasse skal fastholdes til BESKEDER tabel, at identifikatoregenskaben kortlægges til en kolonne med navnet MESSAGE_ID, at tekstegenskaben kortlægges til en kolonne med navnet MESSAGE_TEXT, og at ejendommen navngivet næste besked er en tilknytning til mange-til-én-mangfoldighed der kortlægges til en kolonne med navnet NÆSTE_MESSAGE_ID. (Vær ikke bekymret for de andre detaljer for nu.)

Som du kan se, er XML-dokumentet ikke svært at forstå. Du kan nemt skrive og vedligeholde det manuelt. Uanset hvilken metode du vælger, har dvale nok oplysninger til fuldstændigt at generere alle de SQL-sætninger, der er nødvendige for at indsætte, opdatere, slette og hente forekomster af Besked klasse. Du behøver ikke længere at skrive disse SQL-sætninger manuelt.

Bemærk
Mange Java-udviklere har klaget over "metadatahelvede", der ledsager J2EE-udviklingen. Nogle har foreslået en bevægelse væk fra XML-metadata tilbage til almindelig Java-kode. Selvom vi bifalder dette forslag for nogle problemer, repræsenterer ORM en sag, hvor tekstbaserede metadata virkelig er nødvendige. Dvaletilstand har fornuftige standarder, der minimerer indtastning og en moden dokumenttypedefinition, der kan bruges til automatisk udfyldning eller validering i redaktører. Du kan endda automatisk generere metadata med forskellige værktøjer.

Lad os nu ændre vores første besked, og mens vi er ved at oprette en ny besked tilknyttet den første, som vist i liste 3.

Liste 3. Opdatering af en besked

Session session = getSessionFactory (). OpenSession (); Transaktion tx = session.beginTransaction (); // 1 er det genererede id for den første besked Message message = (Message) session.load (Message.class, new Long (1)); message.setText ("Greetings Earthling"); Besked nextMessage = ny besked ("Tag mig til din leder (tak)"); message.setNextMessage (nextMessage); tx.commit (); session.close (); 

Denne kode kalder tre SQL-sætninger i den samme transaktion:

vælg m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID fra MESSAGES m hvor m.MESSAGE_ID = 1 indsæt i MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID) værdier (2, 'Tag mig til din leder (venligst)', null) opdater MESSAGES sæt MESSAGE_TEXT = 'Hilsen Earthling', NEXT_MESSAGE_ID = 2 hvor MESSAGE_ID = 1 

Læg mærke til, hvordan dvale registrerede ændringen af tekst og næste besked egenskaber for den første besked og automatisk opdateret databasen. Vi har draget fordel af en dvale-funktion kaldet automatisk snavset kontrol: denne funktion sparer os for at eksplicit bede dvale om at opdatere databasen, når vi ændrer tilstanden på et objekt i en transaktion. På samme måde kan du se, at den nye besked blev gjort vedvarende, da der blev oprettet en reference fra den første besked. Denne funktion kaldes cascading gemme: det sparer os for at eksplicit gøre det nye objekt vedholdende ved at ringe Gemme(), så længe det kan nås ved en allerede vedvarende instans. Bemærk også, at rækkefølgen af ​​SQL-sætningerne ikke er den samme som den rækkefølge, hvor vi indstiller egenskabsværdier. Hibernate bruger en sofistikeret algoritme til at bestemme en effektiv ordning, der undgår overtrædelser af databasefremmede nøglebegrænsninger, men som stadig er tilstrækkelig forudsigelig for brugeren. Denne funktion kaldes transaktionsmæssig bagudskrivning.

Hvis vi kører "Hello World" igen, udskrives det:

2 besked (er) fundet: Hilsen Earthling Tag mig til din leder (tak) 

Dette er så vidt vi tager applikationen "Hello World". Nu hvor vi endelig har noget kode i vores bælte, tager vi et skridt tilbage og præsenterer en oversigt over Hibernates vigtigste API'er.

Forståelse af arkitekturen

Programmeringsgrænsefladerne er den første ting, du skal lære om dvale for at bruge den i persistenslaget i din applikation. Et hovedmål med API-design er at holde grænsefladerne mellem softwarekomponenter så smalle som muligt. I praksis er ORM API'er dog ikke særlig små. Vær dog ikke bekymret; du behøver ikke at forstå alle dvale-grænsefladerne på én gang. Figuren nedenfor illustrerer rollerne for de vigtigste dvale-grænseflader i forretnings- og persistenslagene.

Vi viser forretningslaget over persistenslaget, da forretningslaget fungerer som en klient af persistenslaget i en traditionel lagdelt applikation. Bemærk, at nogle enkle applikationer muligvis ikke rent adskiller forretningslogik fra persistenslogik; det er okay - det forenkler blot diagrammet.

Dvaletilstandsgrænsefladerne vist i figuren ovenfor kan omtrent klassificeres som følger:

  • Grænseflader kaldet af applikationer til at udføre grundlæggende CRUD (oprette / læse / opdatere / slette) og forespørgselshandlinger. Disse grænseflader er det vigtigste afhængighedspunkt for applikationsvirksomhed / kontrollogik i dvale. De omfatter Session, Transaktionog Forespørgsel.
  • Grænseflader kaldet af applikationsinfrastrukturkode for at konfigurere dvale, vigtigst af alt, Konfiguration klasse.
  • Ring tilbage grænseflader, der gør det muligt for applikationen at reagere på begivenheder, der forekommer inde i dvale, f.eks Interceptor, Livscyklusog Gyldigt.
  • Grænseflader, der tillader udvidelse af Hibernates kraftfulde kortlægningsfunktionalitet, f.eks Brugertype, CompositeUserTypeog IdentifierGenerator. Disse grænseflader implementeres ved hjælp af applikationsinfrastrukturkode (hvis nødvendigt).

Hibernate gør brug af eksisterende Java API'er, herunder JDBC (Java Database Connectivity), Java Transaction API (JTA) og Java Naming and Directory Interface (JNDI). JDBC giver et rudimentært abstraktionsniveau for funktionalitet, der er fælles for relationelle databaser, så næsten enhver database med en JDBC-driver understøttes af dvale. JNDI og JTA tillader, at dvale integreres med J2EE-applikationsservere.

I dette afsnit dækker vi ikke den detaljerede semantik af Hibernate API-metoder, men kun rollen for hver af de primære grænseflader. Du kan finde de fleste af disse grænseflader i pakken net.sf. dvale. Lad os tage et kort kig på hver grænseflade igen.

Kernegrænsefladerne

De fem kerneinterfaces bruges i næsten alle dvaleapplikationer. Ved hjælp af disse grænseflader kan du gemme og hente vedvarende objekter og kontrollere transaktioner.

Sessionsgrænseflade