Appearance
Spring教程 - 10 JdbcTemplate
在 Java 教程中,我们介绍了使用 JDBC 去操作数据库,但是整体而言,操作起来是比较麻烦的。
JdbcTemplate 是 Spring 框架提供的一个核心 JDBC 辅助类,它简化了传统 JDBC 的复杂操作,可以帮我们处理连接获取、语句创建、结果集遍历和资源释放等工作,让我们可以专注于 SQL 查询和业务逻辑。
下面就来介绍 JdbcTemplate的使用。
10.1 准备工作
1 准备数据库
首先准备一下数据库,我们这里就使用 MySQL 数据库了。
首先创建数据库和表:
sql
-- 创建数据库
CREATE DATABASE foooor_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 创建一张用户表
CREATE TABLE tb_user (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
username VARCHAR(50) NOT NULL COMMENT '用户名',
balance INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '余额',
create_time DATETIME NOT NULL COMMENT '创建时间'
);数据库准备好了!
2 准备项目环境
- 首先创建一个空的 Maven 项目。在 pom.xml 中引入相应的依赖。
这里主要引入 spring-jdbc 的依赖,用来操作数据库。
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.foooor</groupId>
<artifactId>hello-spring</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- 引入spring核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.2.9</version>
</dependency>
<!-- 引入spring jdbc依赖,用于数据库操作 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.2.9</version>
</dependency>
<!-- 引入junit5依赖 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.13.4</version>
</dependency>
<!-- 引入spring 对 junit的支持依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>6.2.11</version>
<scope>test</scope>
</dependency>
<!-- 引入logback依赖,日志框架实现 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.18</version>
</dependency>
<!-- 引入slf4j依赖,日志框架接口门面 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.17</version>
</dependency>
<!-- 引入mysql驱动依赖,用于连接mysql数据库 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- 引入druid依赖,提供数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.27</version>
</dependency>
</dependencies>
</project>- 引入后,记得
右键 --> Maven--> Reload project。
- 创建数据库配置文件
为了方便管理,单独为数据库配置信息创建一个配置文件。
在项目的 resources 目录下创建 jdbc.properties 文件,配置数据的连接信息,如下:
properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/foooor_db?useSSL=false&serverTimezone=UTC
jdbc.username=root
jdbc.password=123456- 创建Spring配置类
创建包,并在包下创建配置类,和前面以注解的方式使用 Spring IoC 的操作一样的。
我这里新建了 com.foooor.hellospring.config 包,并在其下创建 SpringConfig.java (名称自定义)
java
package com.foooor.hellospring.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
@Configuration // 配置类
@ComponentScan("com.foooor.hellospring") // 开启组件扫描,并指定扫描的包
@PropertySource("classpath:jdbc.properties") // 加载外部配置文件
public class SpringConfig {
@Value("${jdbc.driver}") // 读取从配置文件注入的属性值。
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* 配置 Druid 数据源
*/
@Bean
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
/**
* 配置 JdbcTemplate
* 方法的参数,Spring IoC 容器会自动注入对应的 Bean
*/
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}- 首先在类上添加各种注解,包括配置类表示、配置Spring扫描的路径、和外部配置文件的路径;
- 然后在配中配置 Druid 的数据源,通过
@Bean注解创建; - 在配置类中创建
JdbcTemplate,JdbcTemplate依赖DataSource,我们将DataSource作为jdbcTemplate方法的参数即可,这样 Spring IoC 容器会自动帮我们注入。
- 准备数据库实体类
我们查询出数据库的数据,都需要封装为对象进行操作,所以我们一般都需要创建一个 Java 实体类与数据库中的表进行对应。
所以这里创建一个 User.java 实体类,用于对查询到的数据进行封装:
java
package com.foooor.hellospring.pojo;
import java.util.Date;
public class User {
private String id;
private String username;
private Integer balance;
private Date createTime;
// ...getters and setter 略
/**
* 重写 toString 方法,方便打印输出
*/
@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", username='" + username + '\'' +
", balance='" + balance + '\'' +
", createTime=" + createTime +
'}';
}
}- 在查询数据的时候,我们会将数据库的每一条数据封装成一个对象。
准备工作做完了,现在演示一下 JdbcTemplate 的使用。
10.2 JdbcTemplate实现CRUD
下面就使用 JdbcTemplate 实现增删改查。
我们直接编写测试方法进行测试。
1 增删改
增删改放在一起,因为它们调用的方法是一样的。
首先看一下新增数据:
java
package com.foooor.hellospring;
import com.foooor.hellospring.config.SpringConfig;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import java.util.Date;
@SpringJUnitConfig(classes = {SpringConfig.class}) // 指定 Spring 配置文件
public class JdbcTest {
private static final Logger logger = LoggerFactory.getLogger(JdbcTest.class);
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 测试插入用户
*/
@Test
public void testInsert() {
// 1.准备sql
String sql = "insert into tb_user (username, balance, create_time) values (?, ?, ?)";
// 2.执行更新
int rows = jdbcTemplate.update(sql, "zhangsan", 100, new Date());
logger.info("----rows:{}", rows);
}
}- 使用起来很简单,首先准备 sql语句,然后调用 update 方法,传递 sql语句 和 参数即可。
- 上面用到的
update()方法第一个参数是 sql 语句,后面的是可变参数,传递任意个,需要和 sql 占位符对应。或者传递一个 Object 数组也可以。
下面是修改和删除,和新增是一样的,只是 sql 不同而已,也是调用 update() 方法:
java
/**
* 测试更新用户
*/
@Test
public void testUpdate() {
// 1.准备sql
String sql = "update tb_user set balance = balance + ? where id = ?";
// 2.执行更新,金额加100
int rows = jdbcTemplate.update(sql, 100, 5);
logger.info("----rows:{}", rows);
}
/**
* 测试删除用户
*/
@Test
public void testDelete() {
// 1.准备sql
String sql = "delete from tb_user where id = ?";
// 2.执行更新
int rows = jdbcTemplate.update(sql, 5);
logger.info("----rows:{}", rows);
}- 调用的时候,注意传递的参数需要和占位符对应。
和操作 JDBC 比起来,可以看到使用起来非常简单。
2 查询
单独介绍一下查询,操作有一些不同。
查询方式也有多种:
- 查询单个用户
- 查询用户列表
- 查询单个数据,例如查询条目数或最大值。
先从查询单个用户开始,编写测试查询的方法如下:
java
/**
* 根据id查询用户
*/
@Test
public void testSelect() {
// 1.准备sql
String sql = "select * from tb_user where id = ?";
// 2.执行查询
User user = jdbcTemplate.queryForObject(sql, new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getString("id"));
user.setUsername(rs.getString("username"));
user.setBalance(rs.getInt("balance"));
user.setCreateTime(rs.getTimestamp("create_time"));
return user;
}
}, 1); //查询id为1的用户
logger.info("----user:{}", user);
}- 查询单个用户使用
queryForObject方法,第一个参数是 sql;第二个参数是一个接口,我们可以创建一个匿名实现类传入,第二个参数主要是获取数据库每条记录的信息,封装成一个对象返回;第三个以及后面的参数是 sql 中占位符对应的参数。 - 我们只需要将数据库的字段和类属性映射即可。
- 需要注意,查询不到用户会报错,如果需要可以捕获
EmptyResultDataAccessException(没有找到)和IncorrectResultSizeDataAccessException(查询到多个) 异常。
上面的写法已经比原生的 JDBC 要简单很多了,Spring 还帮我们封装了自动映射的类 BeanPropertyRowMapper ,使用它可以帮我们自动映射。
举个栗子:
java
/**
* 根据id查询用户
*/
@Test
public void testSelect2() {
// 1.准备sql
String sql = "select * from tb_user where id = ?";
// 2.执行查询
User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), 1);
logger.info("----user:{}", user);
}new BeanPropertyRowMapper<>(User.class)会帮我们把数据库的字段和User.class进行映射。- 但是需要注意,数据库字段和类的属性需要遵守下划线转驼峰,例如
create_time→createTime。
是不是非常的简单。
上面是查询单个对象,下面介绍一下列表查询。
和查询单个对象基本是一样的,只是使用的方法不同,使用 query 方法,参数都是一样的,如下:
java
/**
* 方式一
* 根据条件查询用户列表
*/
@Test
public void testSelect3() {
// 1.准备sql
String sql = "select * from tb_user where username like ?";
// 2.执行查询
List<User> userList = jdbcTemplate.query(sql, new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getString("id"));
user.setUsername(rs.getString("username"));
user.setBalance(rs.getInt("balance"));
user.setCreateTime(rs.getTimestamp("create_time"));
return user;
}
}, "li%"); // 查询li开头的用户名
logger.info("----user:{}", userList);
}
/**
* 方式二
* 根据条件查询用户列表
*/
@Test
public void testSelect4() {
// 1.准备sql
String sql = "select * from tb_user where username like ?";
// 2.执行查询, 查询li开头的用户名
List<User> userList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class), "li%");
logger.info("----user:{}", userList);
}- 和查询单个对象基本相同,也可以使用
BeanPropertyRowMapper。 - 如果查询没有条件,可以不传递参数。
查询单个数据,例如查询所有用户的数量:
java
/**
* 查询指定条件的用户数量
*/
@Test
public void testSelect5() {
// 1.准备sql
String sql = "select count(*) from tb_user where username like ?";
// 2.执行查询
Integer count = jdbcTemplate.queryForObject(sql, Integer.class, "%li%");
logger.info("----用户数量:{}", count);
}- 上面查询的是名称中包含
li的用户数量,如果没有条件,可以不传递参数。 - 第二个参数是返回结果的类型,我们查询的是条目数量,可以传递
Integer.class或Long.class。
使用 Spring JdbcTemplate 比使用基础的 JDBC 操作起来要方便很多,操作简单,好评。
内容未完......