在实际的企业级应用开发中,却很少有人直接使用原生的 JDBC API 进行开发,这是因为使用 JDBC API 对数据库进行操作十分繁琐,需要我们对每一步都做到“步步把控,处处关心”,例如我们需要手动控制数据库连接的开启,异常处理、事务处理、最后还要手动关闭连接释放资源等等。
Spring 提供了一个 Spring JDBC 模块,它对 JDBC API 进行了封装,其的主要目的降低 JDBC API 的使用难度,以一种更直接、更简洁的方式使用 JDBC API。
使用 Spring JDBC,开发人员只需要定义必要的参数、指定需要执行的 SQL 语句,即可轻松的进行 JDBC 编程,对数据库进行访问。
至于驱动的加载、数据库连接的开启与关闭、SQL 语句的创建与执行、异常处理以及事务处理等繁杂乏味的工作,则都是由 Spring JDBC 完成的。这样就可以使开发人员从繁琐的 JDBC API 中解脱出来,有更多的精力专注于业务的开发。
Spring JDBC 提供了多个实用的数据库访问工具,以简化 JDBC 的开发,其中使用最多就是 JdbcTemplate。
JdbcTemplate
JdbcTemplate 是 Spring JDBC 核心包(core)中的核心类,它可以通过配置文件、注解、Java 配置类等形式获取数据库的相关信息,实现了对 JDBC 开发过程中的驱动加载、连接的开启和关闭、SQL 语句的创建与执行、异常处理、事务处理、数据类型转换等操作的封装。我们只要对其传入SQL 语句和必要的参数即可轻松进行 JDBC 编程。
JdbcTemplate 的全限定命名为 org.springframework.jdbc.core.JdbcTemplate,它提供了大量的查询和更新数据库的方法
导入 JDBC 场景启动器
Spring Boot 将日常企业应用研发中的各种场景都抽取出来,做成一个个的场景启动器(Starter),场景启动器中整合了该场景下各种可能用到的依赖,让用户摆脱了处理各种依赖和配置的困扰。
想要在 Spring Boot 中使用 JDBC 进行数据访问,第一步就是要在 pom.xml 中导入 JDBC 场景启动器:spring-boot-starter-data-jdbc,代码如下。
<!--导入JDBC的场景启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
查看 spring-boot-starter-data-jdbc 的依赖树,可以看到,该场景启动器默认引入了一个数据源:HikariCP,如下图所示。
导入数据库驱动
JDBC 的场景启动器中并没有导入数据库驱动,我们需要根据自身的需求引入所需的数据库驱动。例如,访问 MySQL 数据库时,需要导入 MySQL 的数据库驱动:mysql-connector-java,示例代码如下。
<!--导入数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
Spring Boot 默认为数据库驱动程序做了版本仲裁,所以我们在导入数据库驱动时,可以不再声明版本。需要注意的是,数据库驱动的版本必须与数据库的版本相对应。
常见错误
配置数据源
在导入了 JDBC 场景启动器和数据库驱动后,接下来我们就可以在配置文件(application.properties/yml)中配置数据源了,示例代码(application.yml)如下。
#数据源连接信息
spring:
datasource:
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/bianchengbang_jdbc
driver-class-name: com.mysql.cj.jdbc.Driver
测试
Spring Boot 提供了一个名为 JdbcTemplate 的轻量级数据访问工具,它是对 JDBC 的封装。Spring Boot 对 JdbcTemplate 提供了默认自动配置,我们可以直接使用 @Autowired 或构造函数将它注入到 bean 中使用。
查询
@Autowired
JdbcTemplate jdbcTemplate;
@GetMapping("dept")
public Object hello(){
Dept dept = jdbcTemplate.queryForObject("SELECT * from dept where dept_no = 1", new BeanPropertyRowMapper(Dept.class) );
return dept;
}
@GetMapping("/list")
public Object list(){
List<Dept> list= jdbcTemplate.query("SELECT * from dept ", new BeanPropertyRowMapper(Dept.class) );
return list;
}
注意:
BeanPropertyRowMapper
将数据库查询结果转换为Java类对象。 常应用于使用Spring的JdbcTemplate查询数据库,获取List结果列表,数据库表字段和实体类自动对应。
#新增
jdbcTemplate.update("INSERT INTO `bianchengbang_jdbc`.`dept` (`dept_no`, `dept_name`, `db_source`) VALUES (null, ?,?);", dept.getDept_name(),dept.getDb_source());
#删除
jdbcTemplate.update("DELETE from dept where dept.dept_no = ?", 8);
#修改
...
参考示例:
package net.biancheng.c.dao.impl;
import net.biancheng.c.dao.UserDao;
import net.biancheng.c.entity.User;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.util.List;
@Repository
public class UserDaoImpl implements UserDao {
@Resource
private JdbcTemplate jdbcTemplate;
@Override
public int addUer(User user) {
String sql = "INSERT into `user` (`user`.user_name,`user`.`status`) VALUES(?,?);";
int update = jdbcTemplate.update(sql, user.getUserName(), user.getStatus());
return update;
}
@Override
public int update(User user) {
String sql = "UPDATE `user` SET status=? WHERE user_name=?;";
return jdbcTemplate.update(sql, user.getStatus(), user.getUserName());
}
@Override
public int delete(User user) {
String sql = "DELETE FROM `user` where user_name=?;";
return jdbcTemplate.update(sql, user.getUserName());
}
@Override
public int count(User user) {
String sql = "SELECT COUNT(*) FROM `user` where `status`=?;";
return jdbcTemplate.queryForObject(sql, Integer.class, user.getStatus());
}
@Override
public List<User> getList(User user) {
String sql = "SELECT * FROM `user` where `status`=?;";
return jdbcTemplate.query(sql, new BeanPropertyRowMapper<User>(User.class), user.getStatus());
}
@Override
public User getUser(User user) {
String sql = "SELECT * FROM `user` where `user_id`=?;";
return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), user.getUserId());
}
@Override
public void batchAddUser(List<Object[]> batchArgs) {
String sql = "INSERT into `user` (`user`.user_name,`user`.`status`) VALUES(?,?);";
jdbcTemplate.batchUpdate(sql, batchArgs);
}
}
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for dept
-- ----------------------------
DROP TABLE IF EXISTS `dept` ;
CREATE TABLE `dept` (
`dept_no` int(11) NOT NULL AUTO_INCREMENT,
`dept_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`db_source` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
PRIMARY KEY (`dept_no`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of dept
-- ----------------------------
INSERT INTO `dept` VALUES (1, '开发部', 'bianchengbang_jdbc');
INSERT INTO `dept` VALUES (2, '人事部', 'bianchengbang_jdbc');
INSERT INTO `dept` VALUES (3, '财务部', 'bianchengbang_jdbc');
INSERT INTO `dept` VALUES (4, '市场部', 'bianchengbang_jdbc');
INSERT INTO `dept` VALUES (5, '运维部', 'bianchengbang_jdbc');
SET FOREIGN_KEY_CHECKS = 1;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for tb_user
-- ----------------------------
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
`user_id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名',
`mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号',
`password` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码',
PRIMARY KEY (`user_id`) USING BTREE,
UNIQUE INDEX `username`(`username`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户' ROW_FORMAT = DYNAMIC;