JDBC med Groovy

1. Introduksjon

I denne artikkelen skal vi se på hvordan vi kan stille relasjonsdatabaser med JDBC, ved hjelp av idiomatiske Groovy.

JDBC er, selv om det er relativt lavt nivå, grunnlaget for de fleste ORM-er og andre høyt tilgangsdatatilgangsbiblioteker på JVM. Og vi kan selvfølgelig bruke JDBC direkte i Groovy; det har imidlertid en ganske tungvint API.

Heldigvis for oss bygger Groovy-standardbiblioteket på JDBC for å presentere et grensesnitt som er rent, enkelt og likevel kraftig. Så vi skal utforske Groovy SQL-modulen.

Vi skal se på JDBC i Groovy, uten å vurdere noen rammer som Spring, som vi har andre guider for.

2. JDBC og Groovy Setup

Vi må inkludere groovy-sql-modul blant våre avhengigheter:

 org.codehaus.groovy groovy 2.4.13 org.codehaus.groovy groovy-sql 2.4.13 

Det er ikke nødvendig å liste det eksplisitt hvis vi bruker groovy-all:

 org.codehaus.groovy groovy-all 2.4.13 

Vi finner den nyeste versjonen av groovy, groovy-sql og groovy-all på Maven Central.

3. Koble til databasen

Det første vi må gjøre for å jobbe med databasen, er å koble til den.

La oss introdusere groovy.sql.Sql klasse, som vi bruker for alle operasjoner i databasen med Groovy SQL-modulen.

En forekomst av Kvm representerer en database som vi ønsker å operere på.

Derimot, en forekomst av Kvmer ikke en eneste databaseforbindelse. Vi vil snakke om forbindelser senere, la oss ikke bekymre oss for dem nå; La oss bare anta at alt fungerer magisk.

3.1. Spesifisere tilkoblingsparametere

Gjennom denne artikkelen skal vi bruke en HSQL-database, som er en lett relasjons-DB som mest brukes i tester.

En databaseforbindelse trenger en URL, en driver og tilgangsinformasjon:

Kart dbConnParams = [url: 'jdbc: hsqldb: mem: testDB', bruker: 'sa', passord: '', driver: 'org.hsqldb.jdbc.JDBCDriver']

Her har vi valgt å spesifisere de som bruker a Kart, selv om det ikke er det eneste mulige valget.

Vi kan da få en forbindelse fra Kvm klasse:

def sql = Sql.newInstance (dbConnParams)

Vi får se hvordan du bruker den i de følgende avsnittene.

Når vi er ferdige, bør vi alltid frigjøre eventuelle tilknyttede ressurser:

sql.close ()

3.2. Bruker en Datakilde

Det er vanlig, spesielt i programmer som kjører på en applikasjonsserver, å bruke en datakilde for å koble til databasen.

Når vi ønsker å samle forbindelser eller bruke JNDI, er også en datakilde det mest naturlige alternativet.

Groovy's Kvm klasse godtar datakilder helt fint:

def sql = Sql.newInstance (datakilde)

3.3. Automatisk ressursadministrasjon

Husker å ringe Lukk() når vi er ferdige med en Kvm eksempel er kjedelig; maskiner husker tross alt ting bedre enn vi gjør.

Med Kvm vi kan pakke koden vår i en lukking og ringe Groovy Lukk() automatisk når kontrollen forlater den, selv i tilfelle unntak:

Sql.withInstance (dbConnParams) {Sql sql -> haveFunWith (sql)}

4. Utstede uttalelser mot databasen

Nå kan vi gå videre til de interessante tingene.

Den mest enkle og uspesialiserte måten å uttale seg mot databasen er henrette metode:

sql.execute "create table PROJECT (id integer not null, name varchar (50), url varchar (100))"

I teorien fungerer det både for DDL / DML-utsagn og for spørsmål; Imidlertid tilbyr det enkle skjemaet ovenfor ikke en måte å få tilbake søkeresultatene. Vi legger igjen spørsmål senere.

De henrette metoden har flere overbelastede versjoner, men igjen ser vi på de mer avanserte brukssakene til denne og andre metoder i senere seksjoner.

4.1. Sette inn data

For å sette inn data i små mengder og i enkle scenarier, henrette metoden diskutert tidligere er helt greit.

For tilfeller der vi har generert kolonner (f.eks. Med sekvenser eller automatisk økning) og vi vil vite de genererte verdiene, eksisterer det imidlertid en dedikert metode: executeInsert.

Når det gjelder henrette, vil vi nå se på den mest enkle metoden som er tilgjengelig, noe som gir mer komplekse varianter for en senere del.

Anta at vi har en tabell med en primærnøkkel for automatisk økning (identitet i HSQLDB-språk):

sql.execute "opprett tabell PROJEKT (ID IDENTITET, NAVN VARCHAR (50), URL VARCHAR (100))"

La oss sette inn en rad i tabellen og lagre resultatet i en variabel:

def ids = sql.executeInsert "" "INSERT IN PROJECT (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')" ""

executeInsert oppfører seg akkurat som henrette, men hva returnerer den?

Det viser seg at returverdien er en matrise: radene er de innsatte radene (husk at en enkelt setning kan føre til at flere rader settes inn) og kolonnene er de genererte verdiene.

Det høres komplisert ut, men i vårt tilfelle, som er den desidert vanligste, er det en enkelt rad og en enkelt generert verdi:

assertEquals (0, ids [0] [0])

En påfølgende innsetting vil returnere en generert verdi på 1:

ids = sql.executeInsert "" "INSERT IN PROJECT (NAME, URL) VALUES ('REST with Spring', 'github.com/eugenp/REST-With-Spring')" "" assertEquals (1, ids [0] [ 0])

4.2. Oppdatere og slette data

På samme måte eksisterer det en dedikert metode for modifisering og sletting av data: executeUpdate.

Igjen, dette skiller seg fra henrette bare i returverdien, og vi vil bare se på den enkleste formen.

Returverdien, i dette tilfellet, er et helt tall, antallet berørte rader:

def count = sql.executeUpdate ("UPDATE PROJECT SET URL = '//' + URL") assertEquals (2, count)

5. Spørring av databasen

Ting begynner å bli Groovy når vi spør etter databasen.

Håndterer JDBC ResultatSett klasse er ikke akkurat gøy. Heldigvis for oss tilbyr Groovy en fin abstraksjon over alt dette.

5.1. Iterere over søkeresultater

Mens sløyfer er så gamle stil ... vi er alle i nedleggelser i dag.

Og Groovy er her for å passe vår smak:

sql.eachRow ("SELECT * FROM PROJECT") {GroovyResultSet rs -> haveFunWith (rs)}

De eachRow metoden utsteder spørringen vår mot databasen og kaller en nedleggelse over hver rad.

Som vi kan se, en rad er representert med en forekomst av GroovyResultSet, som er en utvidelse av vanlig gammel ResultatSett med noen få godbiter. Les videre for å finne mer om det.

5.2. Få tilgang til resultatsett

I tillegg til alle ResultatSett metoder, GroovyResultSet tilbyr noen få praktiske verktøy.

Hovedsakelig utsetter den navngitte egenskaper som samsvarer med kolonnenavn:

sql.eachRow ("SELECT * FROM PROJECT") {rs -> assertNotNull (rs.name) assertNotNull (rs.URL)}

Legg merke til hvordan eiendomsnavn er uten store og små bokstaver.

GroovyResultSet gir også tilgang til kolonner ved hjelp av en nullbasert indeks:

sql.eachRow ("SELECT * FROM PROJECT") {rs -> assertNotNull (rs [0]) assertNotNull (rs [1]) assertNotNull (rs [2])}

5.3. Paginering

Vi kan enkelt bla resultatene, dvs. laste bare et delsett som starter fra noen forskyvning opp til noe maksimalt antall rader. Dette er for eksempel en vanlig bekymring i webapplikasjoner.

eachRow og relaterte metoder har overbelastning som godtar en forskyvning og maksimalt antall returnerte rader:

def offset = 1 def maxResults = 1 def rows = sql.rows ('SELECT * FROM PROJECT ORDER BY NAME', offset, maxResults) assertEquals (1, rows.size ()) assertEquals ('REST with Spring', rader [0 ].Navn)

Her, den rader metoden returnerer en liste med rader i stedet for å gjentas over dem som eachRow.

6. Parameteriserte spørsmål og utsagn

Oftere enn ikke er spørsmål og uttalelser ikke fullstendig løst ved kompileringstidspunktet; de har vanligvis en statisk del og en dynamisk del, i form av parametere.

Hvis du tenker på strengkombinasjon, stopp nå og les om SQL-injeksjon!

Vi nevnte tidligere at metodene vi har sett i forrige seksjoner har mange overbelastninger for forskjellige scenarier.

La oss introdusere de overbelastningene som håndterer parametere i SQL-spørsmål og utsagn.

6.1. Strenger With Placeholders

I stil som ligner på vanlig JDBC, kan vi bruke posisjonsparametere:

sql.execute ('INSERT INTO PROJECT (NAME, URL) VALUES (?,?)', 'tutorials', 'github.com/eugenp/tutorials')

eller vi kan bruke navngitte parametere med et kart:

sql.execute ('INSERT INTO PROJECT (NAME, URL) VALUES (: name,: url)', [name: 'REST with Spring', url: 'github.com/eugenp/REST-With-Spring'])

Dette fungerer for henrette, executeUpdate, rader og eachRow. executeInsert støtter også parametere, men signaturen er litt annerledes og vanskeligere.

6.2. Groovy Strings

Vi kan også velge en Groovier-stil ved hjelp av GStrings med plassholdere.

Alle metodene vi har sett erstatter ikke plassholdere i GStrings på vanlig måte; heller, de setter dem inn som JDBC-parametere, og sørger for at SQL-syntaksen er riktig bevart, uten behov for å sitere eller unnslippe noe og dermed ingen risiko for injeksjon.

Dette er helt greit, trygt og groovy:

def name = 'REST with Spring' def url = 'github.com/eugenp/REST-With-Spring' sql.execute "INSERT INTO PROJECT (NAME, URL) VALUES ($ {name}, $ {url})"

7. Transaksjoner og tilkoblinger

Så langt har vi hoppet over en veldig viktig bekymring: transaksjoner.

Vi har faktisk ikke snakket i det hele tatt om hvordan Groovy er Kvm administrerer forbindelser, enten.

7.1. Kortlivede tilkoblinger

I eksemplene som er presentert så langt, hvert spørsmål eller uttalelse ble sendt til databasen ved hjelp av en ny, dedikert forbindelse. Kvm lukker forbindelsen så snart operasjonen avsluttes.

Selvfølgelig, hvis vi bruker en tilkoblingsbasseng, kan effekten på ytelsen være liten.

Fortsatt, hvis vi ønsker å utstede flere DML-uttalelser og spørsmål som en enkelt, atomoperasjon, vi trenger en transaksjon.

For at en transaksjon i utgangspunktet skal være mulig, trenger vi også en forbindelse som spenner over flere utsagn og spørsmål.

7.2. Transaksjoner med hurtigbufret tilkobling

Groovy SQL tillater ikke oss å opprette eller få tilgang til transaksjoner eksplisitt.

I stedet bruker vi medTransaksjon metode med lukking:

sql.withTransaction {sql.execute "" "INSERT IN PROJECT (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')" "" sql.execute "" "INSERT INTO PROJECT (NAME, URL VERDIER ('HVIL med våren', 'github.com/eugenp/REST-With-Spring') "" "}

Inne i lukningen brukes en enkelt databaseforbindelse for alle spørsmål og utsagn.

Videre blir transaksjonen automatisk begått når avslutningen avsluttes, med mindre den avsluttes tidlig på grunn av et unntak.

Imidlertid kan vi også manuelt begå eller tilbakestille den gjeldende transaksjonen med metoder i Kvm klasse:

sql.withTransaction {sql.execute "" "INSERT IN PROJECT (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')" "" sql.commit () sql.execute "" "INSERT INTO PROSJEKT (NAVN, URL) VERDIER ('HVIL med våren', 'github.com/eugenp/REST-With-Spring') "" "sql.rollback ()}

7.3. Bufrede tilkoblinger uten transaksjon

Til slutt, for å gjenbruke en databaseforbindelse uten transaksjonssemantikken beskrevet ovenfor, bruker vi cacheConnection:

sql.cacheConnection {sql.execute "" "INSERT IN PROJECT (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')" "" throw new Exception ('This does not roll back')}

8. Konklusjoner og videre lesing

I denne artikkelen har vi sett på Groovy SQL-modulen og hvordan den forbedrer og forenkler JDBC med nedleggelser og Groovy-strenger.

Vi kan da trygt konkludere med at vanlig JDBC ser litt mer moderne ut med et dryss Groovy!

Vi har ikke snakket om hver eneste funksjon i Groovy SQL; for eksempel har vi utelatt batchbehandling, lagrede prosedyrer, metadata og andre ting.

For mer informasjon, se Groovy-dokumentasjonen.

Implementeringen av alle disse eksemplene og kodebitene finnes i GitHub-prosjektet - dette er et Maven-prosjekt, så det skal være enkelt å importere og kjøre som det er.


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