En guide til Apache Commons DbUtils

1. Oversikt

Apache Commons DbUtils er et lite bibliotek som gjør det lettere å jobbe med JDBC.

I denne artikkelen implementerer vi eksempler for å vise funksjonene og funksjonene.

2. Oppsett

2.1. Maven avhengigheter

Først må vi legge til commons-dbutils og h2 avhengigheter til vår pom.xml:

 commons-dbutils commons-dbutils 1.6 com.h2database h2 1.4.196 

Du finner den nyeste versjonen av commons-dbutils og h2 på Maven Central.

2.2. Test Database

Med våre avhengigheter på plass, la oss lage et skript for å lage tabellene og postene vi vil bruke:

OPPRETT TABELLmedarbeider (id int IKKE NULL PRIMÆR NØKKEL auto_inkrement, fornavn varchar (255), etternavn varchar (255), lønn dobbelt, ansatt dato,); OPPRETT TABELL-e-post (id int IKKE NULL PRIMÆR NØKKEL auto_increment, medarbeiderid int, adresse varchar (255)); INSERT INTO ansatte (fornavn, etternavn, lønn, ansatt dato) VERDIER ('John', 'Doe', 10000.10, to_date ('01 -01-2001 ',' dd-mm-åååå ')); // ... INSERT IN email (ansatteid, adresse) VERDIER (1, '[email protected]'); // ...

Alle eksempler på testtilfeller i denne artikkelen vil bruke en nylig opprettet forbindelse til en H2-minnedatabase:

offentlig klasse DbUtilsUnitTest {privat tilkoblingsforbindelse; @Før offentlige ugyldig setupDB () kaster unntak {Class.forName ("org.h2.Driver"); Streng db = "jdbc: h2: mem:; INIT = runskript fra 'classpath: /employees.sql'"; tilkobling = DriverManager.getConnection (db); } @Efter offentlig annullering closeBD () {DbUtils.closeQuietly (forbindelse); } // ...}

2.3. POJOer

Til slutt trenger vi to enkle klasser:

offentlig klasse ansatt {privat heltal id; privat streng fornavn; privat streng etternavn; privat dobbel lønn; privat dato ansatt dato; // standardkonstruktører, getters og setters} public class Email {private Integer id; privat Heltall ansattId; privat strengadresse; // standardkonstruktører, getters og setters}

3. Introduksjon

DbUtils-biblioteket tilbyr de QueryRunner klasse som hovedinngangssted for det meste av den tilgjengelige funksjonaliteten.

Denne klassen fungerer ved å motta en forbindelse til databasen, en SQL-setning som skal utføres, og en valgfri liste over parametere for å levere verdier til plassholderne i spørringen.

Som vi får se senere, får noen få metoder også en ResultatSetHandler implementering - som er ansvarlig for transformasjon ResultatSett forekomster i objektene applikasjonen forventer.

Selvfølgelig har biblioteket allerede flere implementeringer som håndterer de vanligste transformasjonene, for eksempel lister, kart og JavaBeans.

4. Spørring av data

Nå som vi vet det grunnleggende, er vi klare til å spørre databasen vår.

La oss starte med et raskt eksempel på å skaffe alle postene i databasen som en liste over kart ved hjelp av a MapListHandler:

@Test offentlig ugyldighet gittResultHandler_whenExecutingQuery_thenExpectedList () kaster SQLException {MapListHandler beanListHandler = ny MapListHandler (); QueryRunner runner = ny QueryRunner (); Liste list = runner.query (forbindelse, "VELG * FRA ansatt", beanListHandler); assertEquals (list.size (), 5); assertEquals (list.get (0) .get ("fornavn"), "John"); assertEquals (list.get (4) .get ("firstname"), "Christian"); }

Deretter er her et eksempel på bruk av a BeanListHandler å transformere resultatene til Ansatt forekomster:

@Test offentlig ugyldig gittResultHandler_whenExecutingQuery_thenEmployeeList () kaster SQLException {BeanListHandler beanListHandler = new BeanListHandler (Employee.class); QueryRunner runner = ny QueryRunner (); Liste medarbeiderliste = runner.query (tilkobling, "VELG * FRA ansatt", beanListHandler); assertEquals (ansatteListe.størrelse (), 5); assertEquals (employeeList.get (0) .getFirstName (), "John"); assertEquals (ansatteListe.get (4) .getFirstName (), "Christian"); }

For spørsmål som returnerer en enkelt verdi, kan vi bruke en ScalarHandler:

@Test offentlig ugyldighet givenResultHandler_whenExecutingQuery_thenExpectedScalar () kaster SQLException {ScalarHandler scalarHandler = ny ScalarHandler (); QueryRunner runner = ny QueryRunner (); Strengspørsmål = "VELG TELL (*) FRA ansatt"; lang telling = runner.query (forbindelse, spørring, scalarHandler); assertEquals (count, 5); }

Å lære alt ResultatSerHandler implementeringer, kan du henvise til ResultatSetHandler dokumentasjon.

4.1. Egendefinerte håndtere

Vi kan også lage en egendefinert behandler å overføre til QueryRunnerSine metoder når vi trenger mer kontroll over hvordan resultatene vil bli transformert til gjenstander.

Dette kan gjøres ved å enten implementere ResultatSetHandler grensesnitt eller utvide en av de eksisterende implementeringene som tilbys av biblioteket.

La oss se hvordan den andre tilnærmingen ser ut. La oss først legge til et annet felt i vårt Ansatt klasse:

offentlig klasse ansatt {privat liste e-post; // ...}

La oss nå lage en klasse som utvider BeanListHandler skriv inn og angir e-postlisten for hver ansatt:

offentlig klasse EmployeeHandler utvider BeanListHandler {private Connection connection; offentlig EmployeeHandler (Connection con) {super (Employee.class); this.connection = con; } @ Override offentlig listehåndtak (ResultSet rs) kaster SQLException {List ansatte = super.handle (rs); QueryRunner runner = ny QueryRunner (); BeanListHandler handler = new BeanListHandler (Email.class); Strengspørsmål = "VELG * FRA e-post HVER medarbeiderid =?"; for (Ansatt ansatt: ansatte) {List emails = runner.query (connection, query, handler, employee.getId ()); ansatte.setEmails (e-post); } returnere ansatte; }}

Legg merke til at vi forventer en Forbindelse objekt i konstruktøren slik at vi kan utføre spørsmålene for å få e-postene.

Til slutt, la oss teste koden vår for å se om alt fungerer som forventet:

@Test offentlig ugyldig givenResultHandler_whenExecutingQuery_thenEmailsSetted () kaster SQLException {EmployeeHandler employeeHandler = ny EmployeeHandler (tilkobling); QueryRunner runner = ny QueryRunner (); Liste ansatte = runner.query (forbindelse, "VELG * FRA ansatt", medarbeiderHandler); assertEquals (ansatte.get (0) .getE-poster (). størrelse (), 2); assertEquals (ansatte.get (2) .getE-poster (). størrelse (), 3); }

4.2. Egendefinerte radprosessorer

I eksemplene våre er kolonnenavnene på ansatt tabellen samsvarer med feltnavnene på vår Ansatt klasse (matchingen er ikke bokstavsfølsom). Imidlertid er det ikke alltid tilfelle - for eksempel når kolonnenavn bruker understrekninger for å skille sammensatte ord.

I disse situasjonene kan vi dra nytte av RowProcessor grensesnitt og dets implementeringer for å kartlegge kolonnenavnene til de aktuelle feltene i våre klasser.

La oss se hvordan dette ser ut. La oss først lage en annen tabell og sette inn noen poster i den:

OPPRETT TABELL ansattes legacy (id int IKKE NULL PRIMÆR NØKKEL auto_increment, first_name varchar (255), last_name varchar (255), lønn dobbelt, leid_dato dato,); INSERT INTO employee_legacy (first_name, last_name, lønn, leid_dato) VALUES ('John', 'Doe', 10000.10, to_date ('01 -01-2001 ',' dd-mm-åååå ')); // ...

La oss nå endre vår AnsattHåndterer klasse:

public class EmployeeHandler utvider BeanListHandler {// ... public EmployeeHandler (Connection con) {super (Employee.class, new BasicRowProcessor (new BeanProcessor (getColumnToFieldsMap ()))); // ...} offentlig statisk kart getColumnsToFieldsMap () {Map columnsToFieldsMap = ny HashMap (); columnsToFieldsMap.put ("FIRST_NAME", "fornavn"); columnsToFieldsMap.put ("LAST_NAME", "etternavn"); columnsToFieldsMap.put ("HIRED_DATE", "hireDate"); returner kolonnerToFieldsMap; } // ...}

Legg merke til at vi bruker en BeanProsessor å gjøre den faktiske kartleggingen av kolonner til felt og bare for de som må adresseres.

Til slutt, la oss teste alt er ok:

@Test offentlig ugyldig gittResultHandler_whenExecutingQuery_thenAllPropertiesSetted () kaster SQLException {EmployeeHandler medarbeiderHandler = ny MedarbeiderHåndterer (tilkobling); QueryRunner runner = ny QueryRunner (); Strengspørsmål = "VELG * FRA ansatt_legacy"; Liste ansatte = runner.query (forbindelse, spørring, medarbeiderHandler); assertEquals ((int) ansatte.get (0) .getId (), 1); assertEquals (ansatte.get (0) .getFirstName (), "John"); }

5. Sette inn poster

De QueryRunner klasse gir to tilnærminger for å lage poster i en database.

Den første er å bruke Oppdater() metode og sende SQL-setningen og en valgfri liste over erstatningsparametere. Metoden returnerer antall innsatte poster:

@Test offentlig ugyldig nårInserting_thenInserted () kaster SQLException {QueryRunner runner = ny QueryRunner (); String insertSQL = "INSERT INTO ansatte (fornavn, etternavn, lønn, ansatt dato)" + "VERDIER (?,?,?,?)"; int numRowsInserted = runner.update (tilkobling, insertSQL, "Leia", "Kane", 60000.60, ny dato ()); assertEquals (numRowsInserted, 1); }

Den andre er å bruke sett inn() metode som, i tillegg til SQL-setningen og erstatningsparametrene, trenger en ResultatSetHandler for å transformere de resulterende automatisk genererte nøklene. Returverdien vil være det behandleren returnerer:

@Test offentlig ugyldighet gittHandler_whenInserting_thenExpectedId () kaster SQLException {ScalarHandler scalarHandler = ny ScalarHandler (); QueryRunner runner = ny QueryRunner (); String insertSQL = "INSERT INTO employee (fornavn, etternavn, lønn, ansatt dato)" + "VERDIER (?,?,?,?)"; int newId = runner.insert (tilkobling, insertSQL, scalarHandler, "Jenny", "Medici", 60000.60, ny dato ()); assertEquals (newId, 6); }

6. Oppdatering og sletting

De Oppdater() metoden for QueryRunner klasse kan også brukes til å endre og slette poster fra databasen vår.

Bruken av den er triviell. Her er et eksempel på hvordan du oppdaterer en ansattes lønn:

@Test offentlig ugyldighet gittSalary_whenUpdating_thenUpdated () kaster SQLException {dobbel lønn = 35000; QueryRunner runner = ny QueryRunner (); String updateSQL = "OPPDATER ansatt SET lønn = lønn * 1.1 HVOR lønn <=?"; int numRowsUpdated = runner.update (tilkobling, updateSQL, lønn); assertEquals (numRowsUpdated, 3); }

Og her er en annen for å slette en ansatt med gitt ID:

@Test offentlig ugyldig nårDeletingRecord_thenDeleted () kaster SQLException {QueryRunner runner = ny QueryRunner (); Streng deleteSQL = "SLETT FRA medarbeider HVOR id =?"; int numRowsDeleted = runner.update (tilkobling, deleteSQL, 3); assertEquals (numRowsDeleted, 1); }

7. Asynkrone operasjoner

DbUtils tilbyr AsyncQueryRunner klasse for å utføre operasjoner asynkront. Metodene på denne klassen samsvarer med metodene til QueryRunner klasse, bortsett fra at de returnerer a Framtid forekomst.

Her er et eksempel for å skaffe alle ansatte i databasen, og vente i opptil 10 sekunder for å få resultatene:

@Test offentlig ugyldighet givenAsyncRunner_whenExecutingQuery_thenExpectedList () kaster unntak {AsyncQueryRunner runner = ny AsyncQueryRunner (Executors.newCachedThreadPool ()); EmployeeHandler employeeHandler = ny EmployeeHandler (tilkobling); Strengspørsmål = "VELG * FRA ansatt"; Framtid fremtid = runner.query (forbindelse, spørring, medarbeiderHandler); Liste medarbeiderliste = future.get (10, TimeUnit.SECONDS); assertEquals (ansatteListe.størrelse (), 5); }

8. Konklusjon

I denne opplæringen utforsket vi de mest bemerkelsesverdige funksjonene i Apache Commons DbUtils-biblioteket.

Vi spurte om data og transformerte dem til forskjellige objekttyper, satte inn poster som fikk de genererte primærnøklene og oppdaterte og slettede data basert på et gitt kriterium. Vi benyttet oss også av AsyncQueryRunner klasse for å utføre en spørringsoperasjon asynkront.

Og som alltid kan du finne den fullstendige kildekoden for denne artikkelen på Github.


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