Lente JDBC

1. Overzicht

In dit artikel bespreken we praktische gebruiksscenario's van de Spring JDBC-module.

Alle lessen in Spring JDBC zijn onderverdeeld in vier afzonderlijke pakketten:

  • kern - de kernfunctionaliteit van JDBC. Enkele van de belangrijke klassen onder dit pakket zijn onder meer JdbcTemplate, SimpleJdbcInsert,SimpleJdbcCall en NamedParameterJdbcTemplate.
  • databron - hulpprogramma klassen om toegang te krijgen tot een gegevensbron. Het heeft ook verschillende datasource-implementaties voor het testen van JDBC-code buiten de Jakarta EE-container.
  • voorwerp - DB-toegang op een objectgeoriënteerde manier. Hiermee kunt u query's uitvoeren en de resultaten retourneren als een bedrijfsobject. Het brengt ook de queryresultaten tussen de kolommen en eigenschappen van bedrijfsobjecten in kaart.
  • ondersteuning - ondersteunende klassen voor klassen onder kern en voorwerp pakketjes. Bijv. biedt de SQLException vertaalfunctionaliteit.

2. Configuratie

Laten we om te beginnen beginnen met een eenvoudige configuratie van de gegevensbron (we gebruiken een MySQL-database voor dit voorbeeld):

@Configuration @ComponentScan ("com.baeldung.jdbc") openbare klasse SpringJdbcConfig {@Bean openbare DataSource mysqlDataSource () {DriverManagerDataSource dataSource = nieuwe DriverManagerDataSource (); dataSource.setDriverClassName ("com.mysql.jdbc.Driver"); dataSource.setUrl ("jdbc: mysql: // localhost: 3306 / springjdbc"); dataSource.setUsername ("gastgebruiker"); dataSource.setPassword ("guest_password"); retourneer dataSource; }}

Als alternatief kunnen we ook goed gebruik maken van een ingesloten database voor ontwikkeling of testen - hier is een snelle configuratie die een instantie van de H2-ingesloten database maakt en deze vooraf vult met eenvoudige SQL-scripts:

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

Ten slotte - hetzelfde kan natuurlijk worden gedaan met behulp van XML-configuratie voor de databron:

3. Het JdbcTemplate en Query's uitvoeren

3.1. Basisvragen

De JDBC-sjabloon is de belangrijkste API waarmee we toegang krijgen tot de meeste functionaliteit waarin we geïnteresseerd zijn:

  • maken en sluiten van verbindingen
  • uitvoeren van instructies en opgeslagen procedure-aanroepen
  • itereren over de ResultSet en het retourneren van resultaten

Laten we eerst beginnen met een eenvoudig voorbeeld om te zien wat de JdbcTemplate kan doen:

int resultaat = jdbcTemplate.queryForObject ("SELECTEER AANTAL (*) VAN WERKNEMER", Geheel getal.klasse); 

en hier is ook een eenvoudige INSERT:

public int addEmplyee (int id) {return jdbcTemplate.update ("INVOEGEN IN WERKNEMERSWAARDEN (?,?,?,?)", id, "Bill", "Gates", "VS"); }

Let op de standaardsyntaxis van het verstrekken van parameters - met behulp van het teken `?`. Laten we vervolgens eens kijken naar een alternatief voor deze syntaxis.

3.2. Query's met benoemde parameters

Krijgen ondersteuning voor benoemde parameters, gebruiken we de andere JDBC-sjabloon die door het framework wordt geleverd - de NamedParameterJdbcTemplate.

Bovendien wikkelt dit het JbdcTemplate en biedt een alternatief voor de traditionele syntaxis met '?”Om parameters te specificeren. Onder de motorkap vervangt het de genoemde parameters door JDBC "?" placeholder en afgevaardigden naar de ingepakte JDC-sjabloon om de queries uit te voeren:

SqlParameterSource namedParameters = nieuwe MapSqlParameterSource (). AddValue ("id", 1); retourneer namedParameterJdbcTemplate.queryForObject ("SELECTEER FIRST_NAME VAN WERKNEMER WAAR ID =: id", namedParameters, String.class);

Merk op hoe we de MapSqlParameterSource om de waarden voor de genoemde parameters op te geven.

Laten we bijvoorbeeld eens kijken naar het onderstaande voorbeeld dat eigenschappen van een bean gebruikt om de benoemde parameters te bepalen:

Medewerker medewerker = nieuwe medewerker (); employee.setFirstName ("James"); String SELECT_BY_ID = "SELECTEER AANTAL (*) VAN WERKNEMER WAAR FIRST_NAME =: voornaam"; SqlParameterSource namedParameters = nieuwe BeanPropertySqlParameterSource (medewerker); return namedParameterJdbcTemplate.queryForObject (SELECT_BY_ID, namedParameters, Integer.class);

Merk op hoe we nu gebruik maken van de BeanPropertySqlParameterSource implementaties in plaats van de genoemde parameters zoals voorheen handmatig op te geven.

3.3. Queryresultaten toewijzen aan Java-object

Een andere zeer nuttige functie is de mogelijkheid om queryresultaten toe te wijzen aan Java-objecten - door deze te implementeren de RowMapper koppel.

Bijvoorbeeld: voor elke rij die door de query wordt geretourneerd, gebruikt Spring de row mapper om de java bean te vullen:

public class EmployeeRowMapper implementeert RowMapper {@Override public Employee mapRow (ResultSet rs, int rowNum) gooit SQLException {Employee employee = new Employee (); employee.setId (rs.getInt ("ID")); employee.setFirstName (rs.getString ("FIRST_NAME")); employee.setLastName (rs.getString ("LAST_NAME")); employee.setAddress (rs.getString ("ADDRESS")); terugkeer werknemer; }}

Vervolgens kunnen we de row mapper nu doorgeven aan de query-API en volledig gevulde Java-objecten krijgen:

String query = "SELECTEER * VAN WERKNEMER WAAR ID =?"; Werknemer werknemer = jdbcTemplate.queryForObject (query, nieuw object [] {id}, nieuwe EmployeeRowMapper ());

4. Uitzondering vertaling

Spring komt met zijn eigen hiërarchie voor gegevensuitzonderingen - met DataAccessException als de root-uitzondering - en het vertaalt alle onderliggende ruwe uitzonderingen ernaar.

En dus behouden we ons gezond verstand door niet te hoeven omgaan met uitzonderingen op laag niveau van persistentie en profiteren van het feit dat Spring de uitzonderingen op laag niveau omhult in DataAccessException of een van zijn subklassen.

Dit zorgt er ook voor dat het afhandelingsmechanisme voor uitzonderingen onafhankelijk blijft van de onderliggende database die we gebruiken.

Trouwens, de standaard SQLErrorCodeSQLExceptionTranslatorkunnen wij ook voor onze eigen implementatie zorgen SQLExceptionTranslator.

Hier is een snel voorbeeld van een aangepaste implementatie, waarbij het foutbericht wordt aangepast wanneer er een dubbele sleutelovertreding is, wat resulteert in foutcode 23505 bij gebruik van H2:

openbare klasse CustomSQLErrorCodeTranslator breidt uit SQLErrorCodeSQLExceptionTranslator {@Override beschermd DataAccessException customTranslate (String-taak, String sql, SQLException sqlException) {if (sqlException.getErrorCode () == 23505) {return new. ); } retourneer null; }}

Om deze aangepaste uitzonderingsvertaler te gebruiken, moeten we deze doorgeven aan het JdbcTemplate door te bellen setExceptionTranslator () methode:

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

5. JDBC-bewerkingen met SimpleJdbc-klassen

SimpleJdbc klassen bieden een gemakkelijke manier om SQL-instructies te configureren en uit te voeren. Deze klassen gebruiken databasemetagegevens om basisquery's te maken. SimpleJdbcInsert en SimpleJdbcCall klassen bieden een eenvoudigere manier om invoeg- en opgeslagen procedure-aanroepen uit te voeren.

5.1. SimpleJdbcInsert

Laten we eens kijken naar het uitvoeren van eenvoudige invoeginstructies met minimale configuratie.

De INSERT-instructie wordt gegenereerd op basis van de configuratie van SimpleJdbcInsert en alles wat we nodig hebben is om de tabelnaam, kolomnamen en waarden op te geven.

Laten we eerst een SimpleJdbcInsert:

SimpleJdbcInsert simpleJdbcInsert = nieuwe SimpleJdbcInsert (gegevensbron) .withTableName ("WERKNEMER");

Laten we vervolgens de kolomnamen en -waarden opgeven en de bewerking uitvoeren:

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 ()); retourneer simpleJdbcInsert.execute (parameters); }

Verder, om het database om de primaire sleutel te genererenkunnen we gebruik maken van de executeAndReturnKey () API; we moeten ook de daadwerkelijke kolom configureren die automatisch wordt gegenereerd:

SimpleJdbcInsert simpleJdbcInsert = nieuwe SimpleJdbcInsert (gegevensbron) .withTableName ("WERKNEMER") .usingGeneratedKeyColumns ("ID"); Nummer-id = simpleJdbcInsert.executeAndReturnKey (parameters); System.out.println ("Gegenereerde id -" + id.longValue ());

Ten slotte kunnen we deze gegevens ook doorgeven met behulp van de BeanPropertySqlParameterSource en MapSqlParameterSource.

5.2. Opgeslagen procedures met SimpleJdbcCall

Laten we ook eens kijken naar het uitvoeren van opgeslagen procedures - we zullen gebruik maken van de SimpleJdbcCall abstractie:

SimpleJdbcCall simpleJdbcCall = nieuwe SimpleJdbcCall (gegevensbron) .withProcedureName ("READ_EMPLOYEE"); 
openbare werknemer getEmployeeUsingSimpleJdbcCall (int id) {SqlParameterSource in = nieuwe MapSqlParameterSource (). addValue ("in_id", id); Map out = simpleJdbcCall.execute (in); Werknemer emp = nieuwe werknemer (); emp.setFirstName ((String) out.get ("FIRST_NAME")); emp.setLastName ((String) out.get ("LAST_NAME")); terugkeer emp; }

6. Batchbewerkingen

Nog een eenvoudig gebruik: meerdere bewerkingen samen in batches plaatsen.

6.1. Basisbatchbewerkingen met JdbcTemplate

Gebruik makend van JdbcTemplate, batchbewerkingen kan worden uitgevoerd via de batchUpdate () API.

Het interessante deel hier is het beknopte maar zeer nuttige BatchPreparedStatementSetter implementatie:

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

6.2. Batchbewerkingen gebruiken NamedParameterJdbcTemplate

We hebben ook de mogelijkheid om batchbewerkingen uit te voeren met de NamedParameterJdbcTemplate – batchUpdate () API.

Deze API is eenvoudiger dan de vorige - het is niet nodig om extra interfaces te implementeren om de parameters in te stellen, aangezien het een interne voorbereide statement setter heeft om de parameterwaarden in te stellen.

In plaats daarvan kunnen de parameterwaarden worden doorgegeven aan de batchUpdate () methode als een array van SqlParameterSource.

SqlParameterSource [] batch = SqlParameterSourceUtils.createBatch (workers.toArray ()); int [] updateCounts = namedParameterJdbcTemplate.batchUpdate ("INVOEGEN IN WERKNEMERSWAARDEN (: id,: voornaam,: achternaam,: adres)", batch); retourneer updateCounts;

7. Veer JDBC met veerhuls

Spring Boot biedt een starter spring-boot-starter-jdbc voor het gebruik van JDBC met relationele databases.

Zoals met elke Spring Boot-starter, helpt deze ons ook om onze applicatie snel in gebruik te nemen.

7.1. Afhankelijkheid van Maven

We hebben de spring-boot-starter-jdbc afhankelijkheid als de primaire, evenals een afhankelijkheid voor de database die we zullen gebruiken. In ons geval is dit het geval MySQL:

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

7.2. Configuratie

Spring Boot configureert de gegevensbron automatisch voor ons. We hoeven alleen de eigenschappen in een eigendommen het dossier:

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

Dat is alles, door alleen deze configuraties uit te voeren, is onze applicatie actief en kunnen we deze gebruiken voor andere databasebewerkingen.

De expliciete configuratie die we in de vorige sectie zagen voor een standaard Spring-applicatie, is nu opgenomen als onderdeel van de automatische configuratie van Spring Boot.

8. Conclusie

In dit artikel hebben we gekeken naar de JDBC-abstractie in het Spring Framework, waarbij we de verschillende mogelijkheden van Spring JDBC behandelen met praktische voorbeelden.

Ook hebben we gekeken hoe we snel aan de slag kunnen gaan met Spring JDBC met behulp van een Spring Boot JDBC starter.

De broncode voor de voorbeelden is beschikbaar op GitHub.