h2 JDBC
=======
https://github.com/spring-boot-tutorials/spring-data-h2-jdbc
In this article we will configure Spring Boot to connect to an `h2 `_ database
via JDBC.
Create Initial Code Base
------------------------
- Go to https://start.spring.io/
- Add the following dependencies:
- h2
- Lombok
- JDBC
- Click ``Generate``
Dependencies
------------
Dependencies used in ``pom.xml``
.. code-block:: xml
org.springframework.boot
spring-boot-starter-jdbc
com.mysql
mysql-connector-j
9.1.0
org.projectlombok
lombok
1.18.38
com.h2database
h2
runtime
Properties
----------
In ``src/main/resources/application.properties`` let's add the following properties so the Spring Boot application
can connect to the database
.. code-block:: properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
Model
------
Let's create a new POJO ``src/main/java/com/example/Person.java``
.. code-block:: java
@Data
@SuperBuilder
public class Person {
private Long id;
private String firstName;
private String lastName;
}
RowMapper
---------
Next we will create a RowMapper to convert ResultSet into our POJO Person.
This file will be called ``src/main/java/com/example/PersonRowMapper.java``
.. code-block:: java
public class PersonRowMapper implements RowMapper {
@Override
public Person mapRow(ResultSet rs, int rowNum) throws SQLException {
return Person.builder()
.id(rs.getLong("ID"))
.firstName(rs.getString("FIRST_NAME"))
.lastName(rs.getString("LAST_NAME"))
.build();
}
}
Sql Exception Handler
---------------------
Create a custom SQLErrorCodeSQLExceptionTranslator to handle any SQL execution errors:
.. code-block:: java
public class CustomSQLErrorCodeTranslator extends SQLErrorCodeSQLExceptionTranslator {
@Override
protected DataAccessException customTranslate(String task, String sql, SQLException sqlException) {
if (sqlException.getErrorCode() == 23505) {
return new DuplicateKeyException("Custom Exception translator - Integrity constraint violation.", sqlException);
}
return null;
}
}
Main
----
Now let's use this repository.
Go back to ``MainApplication.java`` and add the following:
.. code-block:: java
@Configuration
@SpringBootApplication
public class MainApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Autowired
private DataSource dataSource;
@Override
public void run(String... args) {
// Custom Exception Handling
jdbcTemplate.setExceptionTranslator(new CustomSQLErrorCodeTranslator());
// 1. Simple Inserts
jdbcTemplate.execute("INSERT INTO PERSON(first_name, last_name) VALUES('Victor', 'Hugo')");
jdbcTemplate.update("INSERT INTO PERSON(first_name, last_name) VALUES (?, ?)", "Bill", "Gates");
// 2. Simple Query
int result = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM PERSON", Integer.class);
System.out.println("2. Number of Persons, " + result);
// 3. Named Parameter Query
SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("id", 1);
String firstName = namedParameterJdbcTemplate.queryForObject("SELECT FIRST_NAME FROM PERSON WHERE ID = :id", namedParameters, String.class);
System.out.println("3. Person with ID=1 has name=" + firstName);
// 4. RowMapper
String query = "SELECT * FROM PERSON WHERE ID = ?";
Person person = jdbcTemplate.queryForObject(query, new PersonRowMapper(), 1);
System.out.println("4. " + person.toString());
// 5. SimpleJDBC
SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(dataSource).withTableName("PERSON");
Map parameters = new HashMap<>();
parameters.put("ID", 1000);
parameters.put("FIRST_NAME", "Jesus");
parameters.put("LAST_NAME", "Christ");
int i = simpleJdbcInsert.execute(parameters);
System.out.println("5. SimpleJDBC returned i=" + i);
// 6. SimpleJDBC with Generated Key Columns
simpleJdbcInsert = new SimpleJdbcInsert(dataSource).withTableName("PERSON")
.usingGeneratedKeyColumns("ID");
parameters = new HashMap<>();
parameters.put("FIRST_NAME", "Jesus");
parameters.put("LAST_NAME", "Christ");
Number id = simpleJdbcInsert.executeAndReturnKey(parameters);
System.out.println("6. SimpleJDBC with Generated Key Columns return id=" + id.longValue());
// 7. Stored Procedure Calls
// SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(dataSource).withProcedureName("READ_EMPLOYEE");
// SqlParameterSource in = new MapSqlParameterSource().addValue("in_id", id);
// Map out = simpleJdbcCall.execute(in);
// System.out.println("7. " + out);
// 8. Batch JdbcTemplate
List people = List.of(
Person.builder().id(100L).firstName("Person100").lastName("Person100").build(),
Person.builder().id(101L).firstName("Person101").lastName("Person101").build(),
Person.builder().id(102L).firstName("Person102").lastName("Person102").build(),
Person.builder().id(103L).firstName("Person103").lastName("Person103").build()
);
int[] batched = jdbcTemplate.batchUpdate("INSERT INTO PERSON VALUES (?, ?, ?)",
new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setLong(1, people.get(i).getId());
ps.setString(2, people.get(i).getFirstName());
ps.setString(3, people.get(i).getLastName());
}
@Override
public int getBatchSize() {
return 4;
}
});
System.out.println("8. " + Arrays.toString(batched));
// 9. Batch NamedParameterJdbcTemplate
SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(List.of(
Person.builder().id(104L).firstName("Person104").lastName("Person104").build(),
Person.builder().id(105L).firstName("Person105").lastName("Person105").build(),
Person.builder().id(106L).firstName("Person106").lastName("Person106").build(),
Person.builder().id(107L).firstName("Person107").lastName("Person107").build()
).toArray());
int[] updateCounts = namedParameterJdbcTemplate.batchUpdate("INSERT INTO PERSON VALUES (:id, :firstName, :lastName)", batch);
System.out.println("9. " + Arrays.toString(updateCounts));
}
}
Run Application
---------------
Open terminal at project root and execute the following:
.. code-block:: sh
mvn spring-boot:run
There should be no errors and the output will display all the CRUD operations.