En guide til Jdbi

1. Introduktion

I denne artikel skal vi se på, hvordan man forespørger på en relationsdatabase med jdbi.

Jdbi er et open source Java-bibliotek (Apache-licens), der bruger lambda-udtryk og refleksion for at give en mere brugervenlig interface på højere niveau end JDBC for at få adgang til databasen.

Jdbi er dog ikke en ORM; selvom det har et valgfrit SQL Object-kortlægningsmodul, har det ikke en session med vedhæftede objekter, et databaseuafhængighedslag og andre klokker og fløjter i en typisk ORM.

2. Jdbi-opsætning

Jdbi er organiseret i en kerne og flere valgfri moduler.

For at komme i gang skal vi bare medtage kernemodulet i vores afhængigheder:

  org.jdbi jdbi3-core 3.1.0 

I løbet af denne artikel viser vi eksempler ved hjælp af HSQL-databasen:

 org.hsqldb hsqldb 2.4.0 test 

Vi kan finde den nyeste version af jdbi3-kerne, HSQLDB og de andre Jdbi-moduler på Maven Central.

3. Oprette forbindelse til databasen

Først skal vi oprette forbindelse til databasen. For at gøre det skal vi specificere forbindelsesparametrene.

Udgangspunktet er Jdbi klasse:

Jdbi jdbi = Jdbi.create ("jdbc: hsqldb: mem: testDB", "sa", "");

Her specificerer vi forbindelses-URL'en, et brugernavn og selvfølgelig en adgangskode.

3.1. Yderligere parametre

Hvis vi har brug for at angive andre parametre, bruger vi en overbelastet metode, der accepterer en Ejendomme objekt:

Egenskaber egenskaber = nye egenskaber (); egenskaber.setProperty ("brugernavn", "sa"); egenskaber.setProperty ("adgangskode", ""); Jdbi jdbi = Jdbi.create ("jdbc: hsqldb: mem: testDB", egenskaber);

I disse eksempler har vi gemt Jdbi forekomst i en lokal variabel. Det er fordi vi bruger det til at sende udsagn og forespørgsler til databasen.

Faktisk bare at ringe skab opretter ikke nogen forbindelse til DB. Det gemmer bare forbindelsesparametrene til senere.

3.2. Brug af en Datakilde

Hvis vi opretter forbindelse til databasen ved hjælp af en DatakildeSom det normalt er tilfældet, kan vi bruge det relevante skab overbelaste:

Jdbi jdbi = Jdbi.create (datakilde);

3.3. Arbejde med håndtag

Faktiske forbindelser til databasen er repræsenteret af forekomster af Håndtere klasse.

Den nemmeste måde at arbejde med håndtag på, og få dem automatisk lukket, er at bruge lambda-udtryk:

jdbi.useHandle (håndtag -> {doStuffWith (håndtag);});

Vi ringer useHandle når vi ikke behøver at returnere en værdi.

Ellers bruger vi med håndtag:

jdbi.withHandle (håndtag -> {return computeValue (håndtag);});

Det er også muligt, men ikke anbefalet, at åbne et forbindelseshåndtag manuelt; i så fald skal vi lukke det, når vi er færdige:

Jdbi jdbi = Jdbi.create ("jdbc: hsqldb: mem: testDB", "sa", ""); prøv (Håndtag = jdbi.open ()) {doStuffWith (håndtag); }

Heldigvis, som vi kan se, Håndtere redskaber Kan lukkes, så det kan bruges med prøv-med-ressourcer.

4. Enkle udsagn

Nu hvor vi ved, hvordan vi opnår en forbindelse, skal vi se, hvordan vi bruger den.

I dette afsnit opretter vi en simpel tabel, som vi bruger i hele artiklen.

At sende erklæringer som f.eks Opret tabel til databasen bruger vi udføre metode:

handle.execute ("Opret tabelprojekt" + "(id-helhedsidentitet, navn varchar (50), url varchar (100))");

udføre returnerer antallet af rækker, der blev påvirket af udsagnet:

int updateCount = handle.execute ("indsæt i projektværdier" + "(1, 'tutorials', 'github.com/eugenp/tutorials')"); assertEquals (1, updateCount);

Faktisk er udførelse kun en bekvemmelighed metode.

Vi ser på mere komplekse brugssager i senere afsnit, men inden vi gør det, skal vi lære at udtrække resultater fra databasen.

5. Forespørgsel om databasen

Det mest ligefremme udtryk, der producerer resultater fra DB, er en SQL-forespørgsel.

For at udstede en forespørgsel med et Jdbi-håndtag skal vi i det mindste:

  1. Opret forespørgslen
  2. vælg, hvordan du skal repræsentere hver række
  3. gentage resultaterne

Vi ser nu på hvert af ovenstående punkter.

5.1. Oprettelse af en forespørgsel

Ikke overraskende, Jdbi repræsenterer forespørgsler som forekomster af Forespørgsel klasse.

Vi kan få en fra et håndtag:

Query query = handle.createQuery ("vælg * fra projekt");

5.2. Kortlægning af resultaterne

Jdbi abstraherer væk fra JDBC ResultSet, som har en ret besværlig API.

Derfor giver det flere muligheder for at få adgang til kolonnerne, der er resultatet af en forespørgsel eller et andet udsagn, der returnerer et resultat. Vi ser nu de enkleste.

Vi kan repræsentere hver række som et kort:

forespørgsel.mapToMap ();

Tasterne på kortet er de valgte kolonnenavne.

Eller når en forespørgsel returnerer en enkelt kolonne, kan vi kortlægge den til den ønskede Java-type:

handle.createQuery ("vælg navn fra projekt"). mapTo (String.class);

Jdbi har indbyggede kortlæggere til mange almindelige klasser. Dem, der er specifikke for et bibliotek eller databasesystem, findes i separate moduler.

Selvfølgelig kan vi også definere og registrere vores kortlæggere. Vi vil tale om det i et senere afsnit.

Endelig kan vi kortlægge rækker til en bønne eller en anden tilpasset klasse. Igen ser vi de mere avancerede muligheder i et dedikeret afsnit.

5.3. Iterere over resultaterne

Når vi har besluttet, hvordan vi skal kortlægge resultaterne ved at kalde den passende metode, vi modtager en ResultatIterabel objekt.

Vi kan derefter bruge den til at gentage resultaterne, en række ad gangen.

Her ser vi på de mest almindelige muligheder.

Vi kan blot samle resultaterne på en liste:

Liste resultater = forespørgsel.mapToMap (). liste ();

Eller til en anden Kollektion type:

Listeresultater = query.mapTo (String.class) .collect (Collectors.toSet ());

Eller vi kan gentage resultaterne som en strøm:

query.mapTo (String.class) .useStream ((Stream stream) -> {doStuffWith (stream)});

Her skrev vi eksplicit strøm variabel for klarhedens skyld, men det er ikke nødvendigt at gøre det.

5.4. Få et enkelt resultat

Som et specielt tilfælde har vi et par dedikerede metoder til rådighed, når vi kun forventer eller er interesseret i en række.

Hvis vi vil højst et resultat, vi kan bruge findFirst:

Valgfri først = forespørgsel.mapToMap (). findFirst ();

Som vi kan se, returnerer den en Valgfri værdi, som kun er til stede, hvis forespørgslen returnerer mindst et resultat.

Hvis forespørgslen returnerer mere end en række, returneres kun den første.

Hvis vi i stedet ønsker det et og kun et resultat, vi bruger findKun:

Date onlyResult = query.mapTo (Date.class) .findOnly ();

Endelig, hvis der er nul resultater eller mere end et, findKun kaster en IllegalStateException.

6. Bindende parametre

Tit, forespørgsler har en fast del og en parametreret del. Dette har flere fordele, herunder:

  • sikkerhed: ved at undgå strengkombination, forhindrer vi SQL-injektion
  • lethed: vi behøver ikke at huske den nøjagtige syntaks for komplekse datatyper såsom tidsstempler
  • performance: den statiske del af forespørgslen kan parses en gang og cachelagres

Jdbi understøtter både positionelle og navngivne parametre.

Vi indsætter positionsparametre som spørgsmålstegn i en forespørgsel eller udsagn:

Forespørgsel positionalParamsQuery = handle.createQuery ("vælg * fra projekt hvor navn =?");

Navngivne parametre starter i stedet med et kolon:

Forespørgsel navngivetParamsQuery = handle.createQuery ("vælg * fra projekt, hvor url som: mønster");

I begge tilfælde, for at indstille værdien af ​​en parameter, bruger vi en af ​​varianterne af binde metode:

positionalParamsQuery.bind (0, "tutorials"); namedParamsQuery.bind ("mønster", "% github.com / eugenp /%");

Bemærk, at indekser i modsætning til JDBC starter ved 0.

6.1. Binding af flere navngivne parametre på én gang

Vi kan også binde flere navngivne parametre sammen ved hjælp af et objekt.

Lad os sige, at vi har denne enkle forespørgsel:

Query query = handle.createQuery ("vælg id fra projekt, hvor navn =: navn og url =: url"); Kortparametre = nyt HashMap (); params.put ("navn", "REST med forår"); params.put ("url", "github.com/eugenp/REST-With-Spring");

Derefter kan vi for eksempel bruge et kort:

query.bindMap (params);

Eller vi kan bruge et objekt på forskellige måder. Her binder vi for eksempel et objekt, der følger JavaBean-konventionen:

query.bindBean (paramsBean);

Men vi kunne også binde et objekts felter eller metoder; for alle de understøttede muligheder, se Jdbi-dokumentationen.

7. Udstedelse af mere komplekse erklæringer

Nu hvor vi har set forespørgsler, værdier og parametre, kan vi gå tilbage til udsagn og anvende den samme viden.

Husk at udføre metode, vi så tidligere, er bare en praktisk genvej.

Faktisk på samme måde som forespørgsler DDL og DML udsagn er repræsenteret som forekomster af klassen Opdatering.

Vi kan få en ved at kalde metoden createUpdate på et håndtag:

Opdater opdatering = handle.createUpdate ("INSERT INTO PROJECT (NAME, URL) VALUES (: name,: url)");

Så på en Opdatering vi har alle de bindingsmetoder, vi har i en Forespørgsel, så afsnit 6. gælder også for opdateringer. url

Erklæringer udføres, når vi kalder, overrasker, udføre:

int-rækker = update.execute ();

Som vi allerede har set returnerer det antallet af berørte rækker.

7.1. Udpakning af automatisk stigning af kolonneværdier

Som et specielt tilfælde, når vi har en indsætningserklæring med automatisk genererede kolonner (typisk automatisk forøgelse eller sekvenser), vil vi muligvis få de genererede værdier.

Så ringer vi ikke udføre, men executeAndReturnGeneratedKeys:

Opdater opdatering = handle.createUpdate ("INSERT INTO PROJECT (NAME, URL)" + "VALUES ('tutorials', 'github.com/eugenp/tutorials')"); ResultBearing generatedKeys = update.executeAndReturnGeneratedKeys ();

ResultatBærende er den samme grænseflade implementeret af Forespørgsel klasse som vi tidligere har set, så vi ved allerede, hvordan vi bruger det:

generatedKeys.mapToMap () .findOnly (). get ("id");

8. Transaktioner

Vi har brug for en transaktion, når vi skal udføre flere udsagn som en enkelt atomoperation.

Som med forbindelseshåndtag introducerer vi en transaktion ved at kalde en metode med en lukning:

handle.useTransaction ((Håndtag h) -> {haveFunWith (h);});

Og som med håndtag lukkes transaktionen automatisk, når lukningen vender tilbage.

Vi skal dog begå eller tilbageføre transaktionen inden hjemkomst:

handle.useTransaction ((Handle h) -> {h.execute ("..."); h.commit ();});

Hvis der dog kastes en undtagelse fra lukningen, ruller Jdbi automatisk transaktionen tilbage.

Som med håndtag har vi en dedikeret metode, iTransaktion, hvis vi vil returnere noget fra lukningen:

handle.inTransaction ((Handle h) -> {h.execute ("..."); h.commit (); return true;});

8.1. Manuel transaktionsstyring

Selvom det generelt ikke anbefales, kan vi også begynde og tæt en transaktion manuelt:

handle.begin (); // ... handle.commit (); handle.close ();

9. Konklusioner og videre læsning

I denne vejledning har vi introduceret kernen i Jdbi: forespørgsler, udsagn og transaktioner.

Vi har udeladt nogle avancerede funktioner, såsom tilpasset række- og kolonnekortlægning og batchbehandling.

Vi har heller ikke drøftet nogen af ​​de valgfri moduler, især SQL Object-udvidelsen.

Alt præsenteres detaljeret i Jdbi-dokumentationen.

Implementeringen af ​​alle disse eksempler og kodestykker findes i GitHub-projektet - dette er et Maven-projekt, så det skal være let at importere og køre som det er.


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