Forår JDBC

1. Oversigt

I denne artikel gennemgår vi praktiske brugssager af Spring JDBC-modulet.

Alle klasser i Spring JDBC er opdelt i fire separate pakker:

  • kerne - kernefunktionaliteten i JDBC. Nogle af de vigtige klasser under denne pakke inkluderer JdbcTemplate, SimpleJdbcInsert,SimpleJdbcCall og NamedParameterJdbcTemplate.
  • datakilde - hjælpeklasser for at få adgang til en datakilde. Det har også forskellige datakildeimplementeringer til test af JDBC-kode uden for Jakarta EE-containeren.
  • objekt - DB-adgang på en objektorienteret måde. Det giver mulighed for at udføre forespørgsler og returnere resultaterne som et forretningsobjekt. Det kortlægger også forespørgselsresultaterne mellem kolonnerne og egenskaberne for forretningsobjekter.
  • support - supportklasser for klasser under kerne og objekt pakker. F.eks. giver den SQLException oversættelsesfunktionalitet.

2. Konfiguration

Til at begynde med, lad os starte med nogle enkle konfigurationer af datakilden (vi bruger en MySQL-database til dette eksempel):

@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 ("gæst_bruger"); dataSource.setPassword ("gæst_passord"); returnere datakilde; }}

Alternativt kan vi også gøre god brug af en integreret database til udvikling eller test - her er en hurtig konfiguration, der opretter en forekomst af H2-integreret database og udfylder den med enkle SQL-scripts:

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

Endelig - det samme kan selvfølgelig gøres ved hjælp af XML-konfiguration til datakilde:

3. Den JdbcTemplate og kørende forespørgsler

3.1. Grundlæggende forespørgsler

JDBC-skabelonen er den vigtigste API, hvorigennem vi får adgang til det meste af den funktionalitet, som vi er interesseret i:

  • oprettelse og lukning af forbindelser
  • udførelse af udsagn og lagrede procedureopkald
  • itererende over ResultSet og returnerer resultater

Lad os først starte med et simpelt eksempel for at se, hvad JdbcTemplate kan gøre:

int resultat = jdbcTemplate.queryForObject ("VÆLG TÆLL (*) FRA MEDARBEJDER", Integer.class); 

og også her er et simpelt INDSÆT:

public int addEmplyee (int id) {return jdbcTemplate.update ("INDSÆT I MEDARBEJDSVÆRDIER (?,?,?,?)", id, "Bill", "Gates", "USA"); }

Læg mærke til standardsyntaxen for at levere parametre - ved hjælp af tegnet `? '. Dernæst - lad os se på et alternativ til denne syntaks.

3.2. Forespørgsler med navngivne parametre

At få understøttelse af navngivne parametre, vi bruger den anden JDBC-skabelon, der leveres af rammen - NamedParameterJdbcTemplate.

Derudover indpakker dette JbdcTemplate og giver et alternativ til den traditionelle syntaks ved hjælp af “?”For at specificere parametre. Under emhætten erstatter den de navngivne parametre til JDBC “?” pladsholder og delegerede til de indpakkede JDCTemplate at udføre forespørgslerne:

SqlParameterSource namedParameters = ny MapSqlParameterSource (). AddValue ("id", 1); returner navngivet navngivetParameterJdbcTemplate.queryForObject ("VÆLG FIRST_NAME FRA MEDARBEJDERE, HVOR ID =: id", navngivet Parametre, String.class);

Læg mærke til, hvordan vi bruger MapSqlParameterSource for at angive værdierne for de navngivne parametre.

Lad os for eksempel se på nedenstående eksempel, der bruger egenskaber fra en bønne til at bestemme de navngivne parametre:

Medarbejdermedarbejder = ny medarbejder (); medarbejder.setFirstnavn ("James"); String SELECT_BY_ID = "VÆLG ANTAL (*) FRA MEDARBEJDER, HVOR FIRST_NAME =: fornavn"; SqlParameterSource namedParameters = ny BeanPropertySqlParameterSource (medarbejder); returner navngivetParameterJdbcTemplate.queryForObject (SELECT_BY_ID, namedParameters, Integer.class);

Bemærk hvordan vi nu bruger BeanPropertySqlParameterSource implementeringer i stedet for at specificere de navngivne parametre manuelt som før.

3.3. Kortlægning af forespørgselsresultater til Java-objekt

En anden meget nyttig funktion er evnen til at kortlægge forespørgselsresultater til Java-objekter - ved at implementere RowMapper interface.

For eksempel - for hver række, der returneres af forespørgslen, bruger Spring rækkeoversigten til at udfylde java-bønnen:

offentlig klasse EmployeeRowMapper implementerer RowMapper {@Override public Employee mapRow (ResultSet rs, int rowNum) kaster SQLException {Medarbejdermedarbejder = ny medarbejder (); medarbejder.setId (rs.getInt ("ID")); medarbejder.setFirstnavn (rs.getString ("FIRST_NAME")); medarbejder.setLastName (rs.getString ("LAST_NAME")); medarbejder.setAddress (rs.getString ("ADRESSE")); tilbagevendende medarbejder }}

Derefter kan vi nu videregive rækkekortet til forespørgsels-API'et og få fuldt udfyldte Java-objekter:

Strengeforespørgsel = "VÆLG * FRA MEDARBEJDER HVOR ID =?"; Medarbejdermedarbejder = jdbcTemplate.queryForObject (forespørgsel, nyt objekt [] {id}, ny EmployeeRowMapper ());

4. Undtagelse Oversættelse

Foråret kommer med sit eget dataundtagelseshierarki ud af kassen - med DataAccessException som rodundtagelsen - og den oversætter alle underliggende rå undtagelser til den.

Og så holder vi vores fornuft ved ikke at skulle håndtere undtagelser på lavt niveau vedholdenhed og drage fordel af det faktum, at foråret indpakker de undtagelser på lavt niveau i DataAccessException eller en af ​​dens underklasser.

Dette holder også undtagelseshåndteringsmekanismen uafhængig af den underliggende database, vi bruger.

Desuden er standard SQLErrorCodeSQLExceptionTranslator, kan vi også levere vores egen implementering af SQLExceptionTranslator.

Her er et hurtigt eksempel på en brugerdefineret implementering, der tilpasser fejlmeddelelsen, når der er en duplikatnøgleovertrædelse, hvilket resulterer i fejlkode 23505, når du bruger H2:

offentlig klasse CustomSQLErrorCodeTranslator udvider SQLErrorCodeSQLExceptionTranslator {@Override beskyttet DataAccessException customTranslate (Streng opgave, String sql, SQLException sqlException) {if (sqlException.getErrorCode () == 23505). ); } returnere null; }}

For at bruge denne brugerdefinerede undtagelsesoversætter skal vi videregive den til JdbcTemplate ved at ringe setExceptionTranslator () metode:

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

5. JDBC-operationer ved hjælp af SimpleJdbc-klasser

SimpleJdbc klasser giver en nem måde at konfigurere og udføre SQL-sætninger på. Disse klasser bruger databasemetadata til at oprette grundlæggende forespørgsler. SimpleJdbcInsert og SimpleJdbcCall klasser giver en nemmere måde at udføre indsættelse og lagrede procedureopkald på.

5.1. SimpleJdbcInsert

Lad os se på udførelse af enkle indsætningserklæringer med minimal konfiguration.

INSERT-sætningen genereres baseret på konfigurationen af SimpleJdbcInsert og alt hvad vi har brug for er at angive tabelnavn, kolonnenavne og værdier.

Lad os først oprette en SimpleJdbcInsert:

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

Lad os derefter give kolonnenavne og -værdier og udføre operationen:

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 ("ADDRESS", emp.getAddress ()); returner simpleJdbcInsert.execute (parametre); }

Yderligere, for at tillade database for at generere den primære nøgle, kan vi gøre brug af executeAndReturnKey () API; vi bliver også nødt til at konfigurere den faktiske kolonne, der automatisk genereres:

SimpleJdbcInsert simpleJdbcInsert = ny SimpleJdbcInsert (dataSource) .withTableName ("EMPLOYEE") .usingGeneratedKeyColumns ("ID"); Nummer-id = simpleJdbcInsert.executeAndReturnKey (parametre); System.out.println ("Genereret id -" + id.longValue ());

Endelig - vi kan også videregive disse data ved hjælp af BeanPropertySqlParameterSource og MapSqlParameterSource.

5.2. Lagrede procedurer med SimpleJdbcCall

Lad os også tage et kig på udførelse af lagrede procedurer - vi gør brug af SimpleJdbcCall abstraktion:

SimpleJdbcCall simpleJdbcCall = nyt SimpleJdbcCall (dataSource) .withProcedureName ("READ_EMPLOYEE"); 
offentlig medarbejder getEmployeeUsingSimpleJdbcCall (int id) {SqlParameterSource in = new MapSqlParameterSource (). addValue ("in_id", id); Kort ud = simpleJdbcCall.execute (in); Medarbejder emp = ny medarbejder (); emp.setFirstName ((String) out.get ("FIRST_NAME")); emp.setLastName ((String) out.get ("LAST_NAME")); returner emp; }

6. Batchoperationer

En anden enkel brugssag - batching af flere operationer sammen.

6.1. Grundlæggende batchoperationer ved hjælp af JdbcTemplate

Ved brug af JdbcTemplate, batchoperationer kan udføres via batchUpdate () API.

Den interessante del her er kortfattet, men yderst nyttig BatchPreparedStatementSetter implementering:

public int [] batchUpdateUsingJdbcTemplate (List medarbejdere) {return jdbcTemplate.batchUpdate ("INSERT TO IN MEDARBEJDSVÆRDIER (?,?,?,?)", nye BatchPreparedStatementSetter () {@Override offentlige ugyldige setValues ​​(PreparedStatment) {ps.setInt (1, workers.get (i) .getId ()); ps.setString (2, workers.get (i) .getFirstName ()); ps.setString (3, workers.get (i). getLastName ()); ps.setString (4, ansatte.get (i) .getAddress ();} @ Override public int getBatchSize () {return 50;}});}

6.2. Batchoperationer ved hjælp af NamedParameterJdbcTemplate

Vi har også mulighed for batching af operationer med NamedParameterJdbcTemplatebatchUpdate () API.

Denne API er enklere end den forrige - det er ikke nødvendigt at implementere ekstra grænseflader for at indstille parametrene, da den har en intern forberedt sætningsindstilling til at indstille parameterværdierne.

I stedet kan parameterværdierne overføres til batchUpdate () metode som en matrix af SqlParameterSource.

SqlParameterSource [] batch = SqlParameterSourceUtils.createBatch (medarbejdere.toArray ()); int [] updateCounts = namedParameterJdbcTemplate.batchUpdate ("INDSÆT I MEDARBEJDSVÆRDIER (: id,: fornavn,: efternavn,: adresse)", batch); returner opdateringCounts;

7. Spring JDBC med Spring Boot

Spring Boot giver en starter spring-boot-starter-jdbc til brug af JDBC med relationsdatabaser.

Som med hver Spring Boot starter hjælper denne os også med at få vores applikation til at køre hurtigt.

7.1. Maven afhængighed

Vi har brug for spring-boot-starter-jdbc afhængighed som den primære samt en afhængighed af den database, som vi bruger. I vores tilfælde er dette MySQL:

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

7.2. Konfiguration

Spring Boot konfigurerer datakilden automatisk for os. Vi skal bare give egenskaberne i en ejendomme fil:

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

Det er det, bare ved kun at udføre disse konfigurationer, er vores applikation i gang, og vi kan bruge den til andre databasefunktioner.

Den eksplicitte konfiguration, vi så i det foregående afsnit for en standard Spring-applikation, er nu inkluderet som en del af Spring Boot-auto-konfiguration.

8. Konklusion

I denne artikel kiggede vi på JDBC-abstraktionen i Spring Framework og dækkede de forskellige muligheder, som Spring JDBC leverede med praktiske eksempler.

Vi undersøgte også, hvordan vi hurtigt kan komme i gang med Spring JDBC ved hjælp af en Spring Boot JDBC starter.

Kildekoden til eksemplerne er tilgængelig på GitHub.