1、概述
在本教程中,我们将介绍 Spring JDBC 模块的实际用例。
Spring JDBC 中的所有类都分为四个独立的包:
- core — JDBC 的核心功能。该包下的一些重要类包括JdbcTemplate、 SimpleJdbcInsert、 SimpleJdbcCall和NamedParameterJdbcTemplate。
- datasource — 用于访问数据源的实用程序类。它还具有用于在 Jakarta EE 容器之外测试 JDBC 代码的各种数据源实现。
- object — 以面向对象的方式访问数据库。它允许运行查询并将结果作为业务对象返回。它还映射业务对象的列和属性之间的查询结果。
- support — 支持core和object包下的类,例如,提供SQLException转换功能
进一步阅读:
2.配置
让我们从数据源的一些简单配置开始。
我们将使用 MySQL 数据库:
@Configuration
@ComponentScan("com.baeldung.jdbc")
public class SpringJdbcConfig {
@Bean
public DataSource mysqlDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/springjdbc");
dataSource.setUsername("guest_user");
dataSource.setPassword("guest_password");
return dataSource;
}
}
或者,我们也可以充分利用嵌入式数据库进行开发或测试。
这是一个创建 H2 嵌入式数据库实例并使用简单 SQL 脚本预填充它的快速配置:
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:jdbc/schema.sql")
.addScript("classpath:jdbc/test-data.sql").build();
}
最后,同样可以使用 XML 配置数据源来完成:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springjdbc"/>
<property name="username" value="guest_user"/>
<property name="password" value="guest_password"/>
</bean>
3. JdbcTemplate和运行查询
3.1。基本查询
JDBC 模板是主要的 API,我们将通过它访问我们感兴趣的大部分功能:
- 创建和关闭连接
- 运行语句和存储过程调用
- 遍历ResultSet并返回结果
首先,我们从一个简单的例子开始,看看JdbcTemplate能做什么:
int result = jdbcTemplate.queryForObject(
"SELECT COUNT(*) FROM EMPLOYEE", Integer.class);
这是一个简单的插入:
public int addEmplyee(int id) {
return jdbcTemplate.update(
"INSERT INTO EMPLOYEE VALUES (?, ?, ?, ?)", id, "Bill", "Gates", "USA");
}
注意使用?提供参数的标准语法 特点。
接下来,让我们看一下这种语法的替代方法。
3.2. 带有命名参数的查询
为了获得对命名参数的支持,我们将使用框架提供的另一个 JDBC 模板 — NamedParameterJdbcTemplate。
此外,它包装了JbdcTemplate并使用 ? 提供了传统语法的替代方案。指定参数。
在幕后,它将命名参数替换为 JDBC ? 占位符并委托给包装的JDCTemplate以运行查询:
SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("id", 1);
return namedParameterJdbcTemplate.queryForObject(
"SELECT FIRST_NAME FROM EMPLOYEE WHERE ID = :id", namedParameters, String.class);
请注意我们如何使用MapSqlParameterSource为命名参数提供值。
让我们看看使用 bean 的属性来确定命名参数:
Employee employee = new Employee();
employee.setFirstName("James");
String SELECT_BY_ID = "SELECT COUNT(*) FROM EMPLOYEE WHERE FIRST_NAME = :firstName";
SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(employee);
return namedParameterJdbcTemplate.queryForObject(
SELECT_BY_ID, namedParameters, Integer.class);
请注意我们现在如何使用BeanPropertySqlParameterSource实现,而不是像以前那样手动指定命名参数。
3.3. 将查询结果映射到 Java 对象
另一个非常有用的特性是能够通过实现RowMapper接口将查询结果映射到 Java 对象。
例如,对于查询返回的每一行,Spring 使用行映射器来填充 java bean:
public class EmployeeRowMapper implements RowMapper<Employee> {
@Override
public Employee mapRow(ResultSet rs, int rowNum) throws 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"));
return employee;
}
}
随后,我们现在可以将行映射器传递给查询 API 并获得完全填充的 Java 对象:
String query = "SELECT * FROM EMPLOYEE WHERE ID = ?";
Employee employee = jdbcTemplate.queryForObject(
query, new Object[] { id }, new EmployeeRowMapper());
4.异常翻译
Spring 自带开箱即用的数据异常层次结构——以DataAccessException作为根异常——并将所有底层原始异常转换为它。
因此,我们通过不处理低级持久性异常来保持理智。我们还受益于 Spring 将低级异常包装在DataAccessException或其子类之一中。
这也使异常处理机制独立于我们正在使用的底层数据库。
除了默认的SQLErrorCodeSQLExceptionTranslator之外,我们还可以提供自己的SQLExceptionTranslator实现。
下面是一个自定义实现的快速示例——在存在重复键违规时自定义错误消息,这在使用 H2 时会导致错误代码 23505 :
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;
}
}
要使用这个自定义异常转换器,我们需要通过调用setExceptionTranslator()方法将其传递给JdbcTemplate :
CustomSQLErrorCodeTranslator customSQLErrorCodeTranslator =
new CustomSQLErrorCodeTranslator();
jdbcTemplate.setExceptionTranslator(customSQLErrorCodeTranslator);
5. 使用 SimpleJdbc 类的 JDBC 操作
SimpleJdbc类提供了一种简单的方法来配置和运行 SQL 语句。这些类使用数据库元数据来构建基本查询。因此,SimpleJdbcInsert和SimpleJdbcCall类提供了一种更简单的方法来运行插入和存储过程调用。
5.1。SimpleJdbcInsert
让我们看一下以最少的配置运行简单的插入语句。
INSERT 语句是根据SimpleJdbcInsert的配置生成的。我们只需要提供表名、列名和值。
首先,让我们创建一个 SimpleJdbcInsert:
SimpleJdbcInsert simpleJdbcInsert =
new SimpleJdbcInsert(dataSource).withTableName("EMPLOYEE");
接下来,让我们提供列名称和值,然后运行操作:
public int addEmplyee(Employee emp) {
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("ID", emp.getId());
parameters.put("FIRST_NAME", emp.getFirstName());
parameters.put("LAST_NAME", emp.getLastName());
parameters.put("ADDRESS", emp.getAddress());
return simpleJdbcInsert.execute(parameters);
}
此外,我们可以使用executeAndReturnKey() API 来允许数据库生成主键。我们还需要配置实际的自动生成列:
SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(dataSource)
.withTableName("EMPLOYEE")
.usingGeneratedKeyColumns("ID");
Number id = simpleJdbcInsert.executeAndReturnKey(parameters);
System.out.println("Generated id - " + id.longValue());
最后,我们还可以使用BeanPropertySqlParameterSource和MapSqlParameterSource传入这些数据。
5.2. 使用SimpleJdbcCall 的存储过程
让我们也看看正在运行的存储过程。
我们将使用SimpleJdbcCall抽象:
SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(dataSource)
.withProcedureName("READ_EMPLOYEE");
public Employee getEmployeeUsingSimpleJdbcCall(int id) {
SqlParameterSource in = new MapSqlParameterSource().addValue("in_id", id);
Map<String, Object> out = simpleJdbcCall.execute(in);
Employee emp = new Employee();
emp.setFirstName((String) out.get("FIRST_NAME"));
emp.setLastName((String) out.get("LAST_NAME"));
return emp;
}
6. 批量操作
另一个简单的用例是将多个操作批处理在一起。
6.1。使用JdbcTemplate 的基本批处理操作
使用JdbcTemplate,可以通过batchUpdate() API运行批处理操作。
这里有趣的部分是简洁但非常有用的BatchPreparedStatementSetter实现:
public int[] batchUpdateUsingJdbcTemplate(List<Employee> employees) {
return jdbcTemplate.batchUpdate("INSERT INTO EMPLOYEE VALUES (?, ?, ?, ?)",
new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setInt(1, employees.get(i).getId());
ps.setString(2, employees.get(i).getFirstName());
ps.setString(3, employees.get(i).getLastName());
ps.setString(4, employees.get(i).getAddress();
}
@Override
public int getBatchSize() {
return 50;
}
});
}
6.2. 使用NamedParameterJdbcTemplate 进行批量操作
我们还可以选择使用NamedParameterJdbcTemplate – batchUpdate() API 进行批处理操作。
此 API 比上一个 API 更简单。因此,不需要实现任何额外的接口来设置参数,因为它有一个内部准备好的语句设置器来设置参数值。
相反,参数值可以作为SqlParameterSource数组传递给batchUpdate()方法。
SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(employees.toArray());
int[] updateCounts = namedParameterJdbcTemplate.batchUpdate(
"INSERT INTO EMPLOYEE VALUES (:id, :firstName, :lastName, :address)", batch);
return updateCounts;
7. Spring JDBC 与 Spring Boot
Spring Boot 提供了一个启动器spring-boot-starter-jdbc用于将 JDBC 与关系数据库一起使用。
与每个 Spring Boot 启动器一样,这个启动器可以帮助我们快速启动和运行我们的应用程序。
7.1。Maven 依赖
我们需要 spring-boot-starter-jdbc依赖项作为主要依赖项。我们还需要我们将使用的数据库的依赖项。在我们的例子中,这是MySQL:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
7.2. 配置
Spring Boot 会自动为我们配置数据源。我们只需要在属性文件中提供属性:
spring.datasource.url=jdbc:mysql://localhost:3306/springjdbc
spring.datasource.username=guest_user
spring.datasource.password=guest_password
就是这样。只需执行这些配置,我们的应用程序就可以启动并运行。我们现在可以将它用于其他数据库操作。
我们在上一节中看到的标准 Spring 应用程序的显式配置现在包含在 Spring Boot 自动配置中。
8. 结论
在本文中,我们研究了 Spring Framework 中的 JDBC 抽象。我们通过实际示例介绍了 Spring JDBC 提供的各种功能。
我们还研究了如何使用 Spring Boot JDBC 启动器快速开始使用 Spring JDBC。
示例的源代码可在 GitHub 上获得。
本文详细介绍了如何在Spring Framework中使用SpringJDBC进行JDBC操作,涵盖了配置、JdbcTemplate、命名参数、异常处理、SimpleJdbc类以及与SpringBoot的集成。通过实例演示,展示了从数据源配置到高级查询技巧和最佳实践。

557

被折叠的 条评论
为什么被折叠?



