Våren JDBC

1. Oversikt

I denne artikkelen vil vi gå gjennom praktiske brukstilfeller av våren JDBC-modulen.

Alle klassene i vår JDBC er delt inn i fire separate pakker:

  • kjerne - kjernefunksjonaliteten til JDBC. Noen av de viktige klassene under denne pakken inkluderer JdbcTemplate, SimpleJdbcInsert,SimpleJdbcCall og NamedParameterJdbcTemplate.
  • datakilde - verktøyklasser for å få tilgang til en datakilde. Den har også forskjellige implementeringer av datakilder for testing av JDBC-kode utenfor Jakarta EE-containeren.
  • gjenstand - DB-tilgang på en objektorientert måte. Det gjør det mulig å utføre spørsmål og returnere resultatene som et forretningsobjekt. Det kartlegger også søkeresultatene mellom kolonnene og egenskapene til forretningsobjekter.
  • Brukerstøtte - støtteklasser for klasser under kjerne og gjenstand pakker. F.eks. gir den SQLException oversettelsesfunksjonalitet.

2. Konfigurasjon

Til å begynne med, la oss starte med en enkel konfigurasjon av datakilden (vi bruker en MySQL-database for dette eksemplet):

@Configuration @ComponentScan ("com.baeldung.jdbc") offentlig klasse SpringJdbcConfig {@Bean public DataSource mysqlDataSource () {DriverManagerDataSource dataSource = new DriverManagerDataSource (); dataSource.setDriverClassName ("com.mysql.jdbc.Driver"); dataSource.setUrl ("jdbc: mysql: // localhost: 3306 / springjdbc"); dataSource.setUsername ("gjest_bruker"); dataSource.setPassword ("gjest_passord"); returner datakilde; }}

Alternativt kan vi også gjøre god bruk av en innebygd database for utvikling eller testing - her er en rask konfigurasjon som oppretter en forekomst av H2-innebygd database og forhåndsutfyller den med enkle SQL-skript:

@Bean public DataSource dataSource () {return new EmbeddedDatabaseBuilder () .setType (EmbeddedDatabaseType.H2) .addScript ("classpath: jdbc / schema.sql") .addScript ("classpath: jdbc / test-data.sql"). Build. (); } 

Til slutt - det samme kan selvfølgelig gjøres ved hjelp av XML-konfigurering for datakilde:

3. Den JdbcTemplate og kjører spørsmål

3.1. Grunnleggende spørsmål

JDBC-malen er den viktigste API-en som vi får tilgang til det meste av funksjonaliteten vi er interessert i:

  • oppretting og lukking av forbindelser
  • utføre uttalelser og lagrede prosedyreanrop
  • gjentar over ResultatSett og returnerer resultater

For det første, la oss starte med et enkelt eksempel for å se hva JdbcTemplate kan gjøre:

int resultat = jdbcTemplate.queryForObject ("VELG TELL (*) FRA MEDARBEIDER", Integer.class); 

og også her er en enkel INSERT:

public int addEmplyee (int id) {return jdbcTemplate.update ("INNFØR I MEDARBEIDERVERDIER (?,?,?,?)", id, "Bill", "Gates", "USA"); }

Legg merke til standardsyntaks for å tilby parametere - bruk tegnet `?`. Neste - la oss se på et alternativ til denne syntaksen.

3.2. Spørringer med navngitte parametere

Å få støtte for navngitte parametere, bruker vi den andre JDBC-malen som leveres av rammeverket - NamedParameterJdbcTemplate.

I tillegg pakker dette inn JbdcTemplate og gir et alternativ til den tradisjonelle syntaksen ved å bruke “?”For å spesifisere parametere. Under panseret erstatter den de nevnte parametrene til JDBC “?” plassholder og delegater til de innpakkede JDCTemplate for å utføre spørsmålene:

SqlParameterSource namedParameters = ny MapSqlParameterSource (). AddValue ("id", 1); returner namedParameterJdbcTemplate.queryForObject ("SELECT FIRST_NAME FROM EMPLOYEE WHERE ID =: id", namedParameters, String.class);

Legg merke til hvordan vi bruker MapSqlParameterSource for å oppgi verdiene for de nevnte parametrene.

La oss for eksempel se på eksemplet nedenfor som bruker egenskaper fra en bønne for å bestemme de nevnte parametrene:

Ansatt ansatt = ny ansatt (); ansatte.setFirstName ("James"); Streng SELECT_BY_ID = "VELG ANTALL (*) FRA MEDARBEIDER HVOR FIRST_NAME =: fornavn"; SqlParameterSource namedParameters = ny BeanPropertySqlParameterSource (ansatt); returner navngittParameterJdbcTemplate.queryForObject (SELECT_BY_ID, namedParameters, Integer.class);

Legg merke til hvordan vi nå bruker BeanPropertySqlParameterSource implementeringer i stedet for å spesifisere de navngitte parametrene manuelt som før.

3.3. Kartlegging av søkeresultater til Java-objekt

En annen veldig nyttig funksjon er muligheten til å kartlegge søkeresultater til Java-objekter - ved å implementere dem RowMapper grensesnitt.

For eksempel - for hver rad som returneres av spørringen, bruker Spring radmapperen til å fylle ut Java-bønnen:

offentlig klasse EmployeeRowMapper implementerer RowMapper {@Override public Employee mapRow (ResultSet rs, int rowNum) kaster SQLException {ansatt ansatt = ny ansatt (); medarbeider.setId (rs.getInt ("ID")); ansatte.setFirstName (rs.getString ("FIRST_NAME")); ansatte.setLastName (rs.getString ("LAST_NAME")); ansatte.setAddress (rs.getString ("ADRESSE")); retur ansatt; }}

Deretter kan vi nå overføre radmapperen til spørrings-API og få fullbefolket Java-objekter:

Strengspørring = "VELG * FRA MEDARBEIDER HVOR ID =?"; Ansatt ansatt = jdbcTemplate.queryForObject (spørring, nytt objekt [] {id}, ny EmployeeRowMapper ());

4. Unntak Oversettelse

Våren kommer med sitt eget data unntak hierarki ut av boksen - med DataAccessException som rot unntak - og det oversetter alle underliggende rå unntak til det.

Og så holder vi sunn fornuft ved ikke å måtte håndtere unntak på lavt nivå vedvarende og drar nytte av det faktum at våren innpakker de unntakene på lav nivå DataAccessException eller en av underklassene.

Dette holder også mekanismen for unntakshåndtering uavhengig av den underliggende databasen vi bruker.

Dessuten er standard SQLErrorCodeSQLExceptionTranslator, kan vi også tilby vår egen implementering av SQLExceptionTranslator.

Her er et raskt eksempel på en tilpasset implementering, som tilpasser feilmeldingen når det er et duplikatnøkkelbrudd, noe som resulterer i feilkode 23505 når du bruker H2:

offentlig klasse CustomSQLErrorCodeTranslator utvider SQLErrorCodeSQLExceptionTranslator {@Override-beskyttet DataAccessException customTranslate (Strengoppgave, String sql, SQLException sqlException) {if (sqlException.getErrorCode () == 23505). ); } returner null; }}

For å bruke denne tilpassede unntaksoversetteren, må vi sende den til JdbcTemplate ved å ringe setExceptionTranslator () metode:

CustomSQLErrorCodeTranslator customSQLErrorCodeTranslator = ny CustomSQLErrorCodeTranslator (); jdbcTemplate.setExceptionTranslator (customSQLErrorCodeTranslator);

5. JDBC-operasjoner ved bruk av SimpleJdbc-klasser

SimpleJdbc klasser gir en enkel måte å konfigurere og utføre SQL-setninger på. Disse klassene bruker databasemetadata for å lage grunnleggende spørsmål. SimpleJdbcInsert og SimpleJdbcCall klasser gir en enklere måte å utføre innlegg og lagrede prosedyreanrop.

5.1. SimpleJdbcInsert

La oss ta en titt på å utføre enkle innsettingsuttalelser med minimal konfigurasjon.

INSERT-setningen genereres basert på konfigurasjonen av SimpleJdbcInsert og alt vi trenger er å oppgi tabellnavnet, kolonnenavn og verdier.

La oss først lage en SimpleJdbcInsert:

SimpleJdbcInsert simpleJdbcInsert = ny SimpleJdbcInsert (dataSource) .withTableName ("MEDARBEIDER");

La oss deretter gi kolonnenavn og verdier, og utføre operasjonen:

public int addEmplyee (Employee emp) {Map parameters = new HashMap (); parameters.put ("ID", emp.getId ()); parameters.put ("FIRST_NAME", emp.getFirstName ()); parameters.put ("LAST_NAME", emp.getLastName ()); parameters.put ("ADRESSE", emp.getAddress ()); returner simpleJdbcInsert.execute (parametere); }

Videre, for å tillate database for å generere primærnøkkelen, kan vi gjøre bruk av executeAndReturnKey () API; vi må også konfigurere den faktiske kolonnen som genereres automatisk:

SimpleJdbcInsert simpleJdbcInsert = ny SimpleJdbcInsert (dataSource) .withTableName ("EMPLOYEE") .usingGeneratedKeyColumns ("ID"); Antall id = simpleJdbcInsert.executeAndReturnKey (parametere); System.out.println ("Generert id -" + id.longValue ());

Til slutt - vi kan også sende inn disse dataene ved å bruke BeanPropertySqlParameterSource og MapSqlParameterSource.

5.2. Lagrede prosedyrer med SimpleJdbcCall

La oss også ta en titt på kjøring av lagrede prosedyrer - vi vil bruke SimpleJdbcCall abstraksjon:

SimpleJdbcCall simpleJdbcCall = ny SimpleJdbcCall (dataSource) .withProcedureName ("READ_EMPLOYEE"); 
offentlig ansatt getEmployeeUsingSimpleJdbcCall (int id) {SqlParameterSource in = new MapSqlParameterSource (). addValue ("in_id", id); Map out = simpleJdbcCall.execute (in); Employee emp = ny ansatt (); emp.setFirstName ((String) out.get ("FIRST_NAME")); emp.setLastName ((String) out.get ("LAST_NAME")); retur emp; }

6. Batchoperasjoner

En annen enkel brukstilfelle - batching av flere operasjoner sammen.

6.1. Grunnleggende batchoperasjoner ved bruk av JdbcTemplate

Ved hjelp av JdbcTemplate, Batch Operations kan utføres via batchUpdate () API.

Den interessante delen her er kortfattet, men svært nyttig BatchPreparedStatementSetter gjennomføring:

public int [] batchUpdateUsingJdbcTemplate (List workers) {return jdbcTemplate.batchUpdate ("INSERT IN TO MEDARBEIDER VALUES (?,?,?,?)", new BatchPreparedStatementSetter () {@Override public void setValues ​​(PreparedStatment) {ps.setInt (1, ansatte.get (i) .getId ()); ps.setString (2, ansatte.get (i) .getFirstName ()); ps.setString (3, ansatte.get (i). getLastName ()); ps.setString (4, ansatte.get (i) .getAddress ();} @ Override public int getBatchSize () {retur 50;}});}

6.2. Batchoperasjoner ved hjelp av NamedParameterJdbcTemplate

Vi har også muligheten for batching-operasjoner med NamedParameterJdbcTemplatebatchUpdate () API.

Denne API-en er enklere enn den forrige - det er ikke nødvendig å implementere ekstra grensesnitt for å sette parametrene, siden den har en intern klargjort setningsinnstiller for å angi parameterverdiene.

I stedet kan parameterverdiene overføres til batchUpdate () metoden som en rekke SqlParameterSource.

SqlParameterSource [] batch = SqlParameterSourceUtils.createBatch (ansatte.tilArray ()); int [] updateCounts = namedParameterJdbcTemplate.batchUpdate ("INSERT IN TO EMPLOYEE VALUES (: id,: firstName,: lastName,: address)", batch); return updateCounts;

7. Vår JDBC med vårstøvel

Spring Boot gir en startpakke spring-boot-starter-jdbc for bruk av JDBC med relasjonsdatabaser.

Som med hver Spring Boot starter, hjelper denne oss også med å få søknaden vår i gang raskt.

7.1. Maven avhengighet

Vi trenger spring-boot-starter-jdbc avhengighet som den primære, samt en avhengighet for databasen vi skal bruke. I vårt tilfelle er dette MySQL:

 org.springframework.boot spring-boot-starter-jdbc mysql mysql-connector-java runtime 

7.2. Konfigurasjon

Spring Boot konfigurerer datakilden automatisk for oss. Vi trenger bare å oppgi eiendommene i en eiendommer fil:

spring.datasource.url = jdbc: mysql: // localhost: 3306 / springjdbc spring.datasource.username = guest_user spring.datasource.password = guest_password

Det er det, bare ved å bare gjøre disse konfigurasjonene, er applikasjonen vår i gang, og vi kan bruke den til andre databaser.

Den eksplisitte konfigurasjonen vi så i forrige seksjon for en standard Spring-applikasjon, er nå inkludert som en del av Spring Boot auto-konfigurasjon.

8. Konklusjon

I denne artikkelen så vi på JDBC-abstraksjonen i Spring Framework, og dekker de forskjellige funksjonene som Spring JDBC gir med praktiske eksempler.

Vi så også på hvordan vi raskt kan komme i gang med Spring JDBC ved hjelp av en Spring Boot JDBC starter.

Kildekoden for eksemplene er tilgjengelig på GitHub.