20. Data(二)-JdbcTemplate 详解
20. Data(二)-JdbcTemplate 详解
前言
本节将介绍如何使用JDBC
核心类来控制基本的JDBC
处理,包括错误处理。
数据库准备
本文已mysql5.7
数据库为例:
DROP TABLE IF EXISTS tb_student;
CREATE TABLE tb_student (
id int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
name varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '姓名',
sex tinyint(1) DEFAULT NULL COMMENT '性别',
age int(11) DEFAULT NULL COMMENT '年龄',
grade varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '年级',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
INSERT INTO tb_student VALUES (1, '张三', 1, 14, '初中');
INSERT INTO tb_student VALUES (2, '李四', 1, 16, '高中');
引入依赖
<!--jdbctemplate 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
配置数据源
spring:
datasource:
#数据库驱动完整类名
driver-class-name: com.mysql.jdbc.Driver
#数据库连接url
url: jdbc:mysql://127.0.0.1:3306/spring-boot-data-learn
#数据库用户名
username: root
#数据库密码
password: 123456
jdbc:
template:
fetch-size: -1
max-rows: -1
#查询超时。默认是使用JDBC驱动程序的默认配置。如果没有指定持续时间后缀,则使用seconds。
query-timeout:
spring.jdbc.template.max-rows
: 将此 Statement
对象生成的所有 ResultSet
对象可以包含的最大行数限制设置为给定数。最大以后的数据会被丢掉,设置这个参数虽然可以避免报内存错误,不过此方法局限性比较大,一般情况下是需要获取所有符合条件的数据。这个方法和limit
类似。默认值-1
,使用JDBC
驱动程序的默认配置。
spring.jdbc.template.fetch-size
:为 JDBC 驱动程序提供一个提示,它提示此 Statement
生成的 ResultSet
对象需要更多行时应该从数据库获取的行数。Spring Boot 中默认值-1
,使用JDBC
驱动程序的默认配置(默认值为0
一次性获取数据),在自动提交模式下无效,需设置autocommit
为false
。
jdbc fetch-size
实现原理:
1、先在服务端执行查询后将数据缓存在服务端。
2、java 端获取数据时,利用服务端游标进行指针跳动,如果 fetchSize 为 1000,则一次性跳动 1000 条,返回给 java 端缓存起来。(耗时较短,跳动次数为 N/1000)
3、在调用 next 函数时,优先从缓存中取数
JdbcTemplate 自动配置
Spring 的JdbcTemplate
和NamedParameterJdbcTemplate
类在 Spring Boot 中自动配置的,你可以直接将它们@Autowire
到你自己的bean
中。
@Component
public class StudentDao {
private final JdbcTemplate jdbcTemplate;
public StudentDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void select(){
this.jdbcTemplate.queryForList("select * from tb_student");
}
}
执行 SQL 打印配置
logging:
level:
org.springframework.jdbc.core.JdbcTemplate: DEBUG
JdbcTemplate 使用
JdbcTemplate
是JDBC
核心包中的中心类,它处理资源的创建和释放,这有助于避免常见错误,比如忘记关闭连接。它执行核心JDBC
工作流的基本任务(如语句创建和执行),而让应用程序代码提供SQL
并提取结果。
JdbcTemplate
类功能如下:
- 运行 SQL 查询
- update 语句和存储过程调用
- 对 ResultSet 实例进行迭代并提取返回的参数值。
- 捕获 JDBC 异常并将其转换为泛型, 异常层次结构定义在 org.springframework.dao 包中。
查询(select)
下面的查询获取行数:
public Integer count() {
return this.jdbcTemplate.queryForObject("select count(*) from tb_student", Integer.class);
}
下面的查询使用了一个绑定变量:
public Integer countByName(String name) {
return this.jdbcTemplate.queryForObject("select count(*) from tb_student where name=?", Integer.class, name);
}
@Test
void daoTest() {
Integer count = studentDao.countByName("张三");
}
SQL statement [select count(*) from tb_student where name='张三']
下面的查询查找一个字符串:
public String selectName(Integer id) {
return this.jdbcTemplate.queryForObject("select name from tb_student where id=?", String.class, id);
}
@Test
void daoTest() {
studentDao.selectName(1);
}
SQL statement [select name from tb_student where id=1]
查询并填充单个对象:
新建实体对象:
public class Student implements Serializable {
private Integer id;
private String name;
private Integer sex;
private Integer age;
private String grade;
//get set
}
新建查询:
public Student selectById(Integer id) {
return this.jdbcTemplate.queryForObject("select * from tb_student where id=?", (resultSet, rowNum) -> {
Student student = new Student();
student.setId(resultSet.getInt("id"));
student.setName(resultSet.getString("name"));
student.setSex(resultSet.getInt("sex"));
student.setAge(resultSet.getInt("age"));
student.setGrade(resultSet.getString("grade"));
return student;
}, id);
}
测试:
Student student=studentDao.selectById(1);
Student{
id=1, name='张三', sex=1, age=14, grade='初中'}
查询并填充 List 对象:
public List<Student> list() {
return this.jdbcTemplate.query("select * form tb_student", (resultSet, rowNum) -> {
Student student = new Student();
student.setId(resultSet.getInt("id"));
student.setName(resultSet.getString("name"));
student.setSex(resultSet.getInt("sex"));
student.setAge(resultSet.getInt("age"));
student.setGrade(resultSet.getString("grade"));
return student;
});
}
上面填充单个对象和List
对象,有重复的代码,删除两个RowMapper
lambda
表达式中出现的重复,并将它们提取到一个字段中,然后根据需要由DAO
方法引用,这样做是有意义的。
private final RowMapper<Student> studentRowMapper = (resultSet, rowNum) -> {
Student student = new Student();
student.setId(resultSet.getInt("id"));
student.setName(resultSet.getString("name"));
student.setSex(resultSet.getInt("sex"));
student.setAge(resultSet.getInt("age"));
student.setGrade(resultSet.getString("grade"));
return student;
};
public List<Student> list() {
return this.jdbcTemplate.query("select * from tb_student", studentRowMapper);
}
Update(INSERT, UPDATE, DELETE)
可以使用update(..)
方法执行插入
、更新
和删除
操作。
插入数据:
public void insert(Student student) {
this.jdbcTemplate.update("insert into tb_student (name,sex,age,grade) value (?,?,?,?)",
student.getName(), student.getSex(), student.getSex(), student.getGrade());
}
测试
@Test
void daoTest() {
Student student = new Student();
student.setName("王五");
student.setSex(1);
student.setAge(20);
student.setGrade("大学");
studentDao.insert(student);
}
SQL statement [insert into tb_student (name,sex,age,grade) value ('王五',1,20,'大学')]
更新数据
this.jdbcTemplate.update(
"update tb_student set grade = ? where id = ?",
"大学", 2);
删除数据
this.jdbcTemplate.update(
"delete from tb_student where id = ?",
2);
其它操作
可以使用execute(..)
方法运行任意SQL
。因此,该方法经常用于DDL
语句。
this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");
下面的例子调用了一个存储过程:
this.jdbcTemplate.update(
"call SUPPORT.REFRESH_ACTORS_SUMMARY(?)",
Long.valueOf(unionId));
批量更新:
public void batchUpdate(List<Student> students) {
this.jdbcTemplate.batchUpdate("insert into tb_student (name,sex,age,grade) value (?,?,?,?)", new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setString(1, students.get(i).getName());
ps.setInt(2, students.get(2).getSex());
}
@Override
public int getBatchSize() {
return students.size();
}
});
}
总结
以上把JdbcTemplate
常见的操作实践了一遍,详细的细节可以参考官方文档。jdbc-core