在 Spring JDBC 中访问数据库最重要的就是 JdbcTemplate
,其提供了对数据库进行增删改查所需要的各种方法,尤其是查询,提供的方法有例如:query
, queryForObject
, queryForList
, update
(插入修改删除), execute
(较为通用) 等。
建立好 Spring Boot 项目,并引入 Lombok, JDBC 依赖后,可以编写一个如下一个访问数据库的 DAO:
package com.delicate.springjdbcdemo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
@Slf4j
@Repository
public class FooDAO {
@Autowired
private JdbcTemplate jdbcTemplate;
public void insertData() {
// insert data
Arrays.asList('b', 'c').forEach(bar -> {
jdbcTemplate.update("INSERT INTO FOO(BAR) VALUES (?)", bar);
});
}
public void listData() {
// query for a result
log.info("Count: {}", jdbcTemplate.queryForObject("SELECT COUNT(*) FROM FOO", Long.class));
// query for a result list of a field in the table
List<String> barList = jdbcTemplate.queryForList("SELECT BAR FROM FOO", String.class);
barList.forEach(bar -> log.info("Bar: {}", bar));
// query for an object list
// 从数据库查询并获取对象列表,实现 RowMapper 的一个匿名内部类建立数据库查询结果和 Foo 间的映射信息
List<Foo> fooList = jdbcTemplate.query("SELECT * FROM FOO", new RowMapper<Foo>() {
@Override
public Foo mapRow(ResultSet resultSet, int i) throws SQLException {
return Foo.builder()
.id(resultSet.getLong(1))
.bar(resultSet.getString(2))
.build();
}
});
fooList.forEach(foo -> log.info("Foo: {}", foo));
}
}
insertData()
方法演示如何使用 jdbcTemplate
对象插入数据;
listData()
方法演示如何使用 jdbcTemplate
对象查询查询获取域的列表、对象列表等信息;(注意 Foo 类需要使用 @Data
和 @Builder
进行注解,Foo.java 代码如下)
package com.delicate.springjdbcdemo;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class Foo {
private long id;
private String bar;
}
@Data
注解后自动“写入” getter,setter 方法,不用再自己写;
@Builder
注解后则提供了一个构造方法,之后可以调用 Foo.builder()
一系列方法构建 Foo
对象(如上);
下面扩展介绍一个可以更方便地使用 JdbcTemplate
的一个类:SimpleJdbcInsert
,这是 Spring JDBC 提供的一个辅助类。
首先需要将 SimpleJdbcInsert
的对象注入到 Spring 容器中:
@Bean
@Autowired
public SimpleJdbcInsert simpleJdbcInsert(JdbcTemplate jdbcTemplate) {
return new SimpleJdbcInsert(jdbcTemplate).withTableName("FOO").usingGeneratedKeyColumns("ID");
}
可以将以上代码块加到合适的类中通过 @Bean
注解完成注入,
之后可以在上文的 FooDAO
类代码中加入以下SimpleJdbcInsert
的属性并使用 @Autowired
自动注入:
@Autowired
private SimpleJdbcInsert simpleJdbcInsert;
然后对 insertData() 方法代码作以下修改:
public void insertData() {
// insert data demo
Arrays.asList('b', 'c').forEach(bar -> {
jdbcTemplate.update("INSERT INTO FOO(BAR) VALUES (?)", bar);
});
HashMap<String, String> valueMap = new HashMap<>();
valueMap.put("BAR", "Allen");
Number id = simpleJdbcInsert.executeAndReturnKey(valueMap);
log.info("ID of Allen: {}", id.longValue());
}
这就实现了使用 SimpleJdbcInsert
方式的插入。
SQL 批处理
Spring JDBC 中批处理可以通过 JdbcTemplate
和 NamedParameterJdbcTemplate
中的 batchUpdate
方法来实现,具体方式如下:
先看对应的 DAO 的代码:
package com.delicate.springjdbcdemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
import org.springframework.stereotype.Repository;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
@Repository
public class BatchFooDAO {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public void batchInsert() {
jdbcTemplate.batchUpdate("INSERT INTO FOO(BAR) VALUES(?)",
new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement preparedStatement, int i) throws SQLException {
preparedStatement.setString(1, "BAR-" + i);
}
@Override
public int getBatchSize() {
return 3;
}
});
List<Foo> foos = new ArrayList<>();
foos.add(Foo.builder().id(100L).bar("BAR-100").build());
foos.add(Foo.builder().id(101L).bar("BAR-101").build());
namedParameterJdbcTemplate.batchUpdate("INSERT INTO FOO(ID, BAR) VALUES(:id, :bar)",
SqlParameterSourceUtils.createBatch(foos));
}
}
第一种使用 JdbcTemplate
的 batchUpdate
的方式需要在 batchUpdate
中传入一个 BatchPreparedStatementSetter
的实现类,其中实现的 setValues
方法对批量执行的 SQL 语句中的 “?
” 进行复制,preparedStatement.setString()
方法中的第一个参数表示是第几个 “?
”;getBatchSize
方法的返回值即执行几次该 SQL 语句,此代码中返回 3,则插入 3 个值。
第二种使用 NamedParameterJdbcTemplate
的 batchUpdate
方式较为简单,理解也比较容易,直接看代码应该挺清楚了,批处理的 SQL 语句中不再用 “?
” 作为占位符,而是使用 “: 域名
” 的形式,然后使用 SqlParameterSourceUtils
提供的 createBatch
方法从一个 Foo
对象列表(foos
)中获取批处理该 SQL 语句所需要的参数列表。