文章目录
视频:单行数据查询与自定义RowMapper接口
18.访问数据库
Spring Boot 框架为 SQL 数据库提供了广泛的支持,既有用 JdbcTemplate 直接访问 JDBC,同时支持“object relational mapping”技术(如 HibernateMyBatis)。Spring Data 独立的项目提供对多种关系型和非关系型数据库的 访问支持。比如 MySQL, Oracle , MongoDB , Redis, R2DBC,Apache Solr,Elasticsearch…
Spring Boot 也支持嵌入式数据库比如 H2, HSQL, and Derby。这些数据库只需要提供 jar 包就能在内存中维护 数据。我们这章访问关系型数据库。
DataSource
通常项目中使用 MySQL,Oracle,PostgreSQL 等大型关系数据库。Java 中的 jdbc 技术支持了多种关系型数据库 的访问。在代码中访问数据库,我们需要知道数据库程序所在的 ip,端口,访问数据库的用户名和密码以及数据 库的类型信息。以上信息用来初始化数据源,数据源也就是 DataSource。数据源表示数据的来源,从某个 ip 上的 数据库能够获取数据。javax.sql.DataSource 接口表示数据源,提供了标准的方法获取与数据库绑定的连接对象 (Connection)。 javax.sql.Connection 是连接对象,在 Connection 上能够从程序代码发送查询命令,更新数据的语句给数据库; 同时从 Connection 获取命令的执行结果。
DataSource 在 application 配置文件中以 spring.datasource.*作为配置项。类似下面的代码:
spring.datasource.url=jdbc:mysql://localhost/mydb
spring.datasource.username=dbuser
spring.datasource.password=dbpass
DataSourceProperties.java 是数据源的配置类,更多配置参考这个类的属性。
@ConfigurationProperties(prefix = “spring.datasource”)
public class DataSourceProperties implements BeanClassLoaderAware,
InitializingBean {
}
- Spring Boot 能够从 spring.datasource.url 推断所使用的数据驱动类,如果需要特殊指定请设置 spring.datasource.driver-class-name 为驱动类的全限定名称。Spring Boot 支持多种数据库连接池,优先使用 HikariCP,其次是 Tomcat pooling,再次是 Commons DBCP2, 如果以上都没有,最后会使用 Oracle UCP 连接池。当项目中 starter 依赖了 spring-boot-starter-jdbc 或者 spring-boot-starter-data-jpa 默认添加 HikariCP 连接池依赖,也就是默认使用 HikariCP 连接池。
JdbcTemplate
使用 JdbcTemplate 我们提供自定义 SQL, Spring 执行这些 SQL 得到记录结果集。JdbcTemplate 和 NamedParameterJdbcTemplate 类是自动配置的,您可以@Autowire 注入到自己的 Bean 中。开箱即用。 JdbcTemplate 执行完整的 SQL 语句,我们将 SQL 语句拼接好,交给 JdbcTemplate 执行,JdbcTemplate 底层 就是使用 JDBC 执行 SQL 语句。是 JDBC 的封装类而已。
NamedParameterJdbcTemplate 可以在 SQL 语句部分使用“:命名参数”作为占位符, 对参数命名,可读性更 好。NamedParameterJdbcTemplate 包装了 JdbcTemplate 对象,“:命名参数”解析后,交给 JdbcTemplate 执行 SQL
语句。
JdbcTemplateAutoConfiguration 自动配置了 JdbcTemplate 对象,交给 JdbcTemplateConfiguration 创建了 JdbcTemplate 对象。并对 JdbcTemplate 做了简单的初始设置(QueryTimeout,maxRows 等)。
访问数据库先准备数据库的 script。SpringBoot 能够自动执行 DDL,DML 脚本。两个脚本文件名称默认是 schema.sql 和 data.sql。脚本文件在类路径中自动加载。
always:总是执行数据库初始化脚本
never:禁用数据库初始化
创建数据库
/*
Navicat Premium Data Transfer
Source Server : 本地数据库
Source Server Type : MySQL
Source Server Version : 80026 (8.0.26)
Source Host : localhost:3306
Source Schema : school
Target Server Type : MySQL
Target Server Version : 80026 (8.0.26)
File Encoding : 65001
Date: 29/03/2025 21:58:40
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`stuid` char(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`major` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `stuid_unique`(`stuid` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES (1, '烟雨1', '1001', '计算机应用技术');
INSERT INTO `student` VALUES (2, '烟雨2', '1002', '软件技术');
SET FOREIGN_KEY_CHECKS = 1;
创建项目
- 安装 lombok 插件
schema.sql
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`stuid` char(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`major` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `stuid_unique`(`stuid` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
data.sql
INSERT INTO `student` VALUES (1, '烟雨1', '1001', '计算机应用技术');
INSERT INTO `student` VALUES (2, '烟雨2', '1002', '软件技术');
配置数据源
- application.properties
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.datasource.url=jdbc:mysql://localhost:3306/blog?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
#spring.datasource.username=root
#spring.datasource.password=123456
#配置数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/school?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=yanyu666
#执行数据库脚本 建表和插入数据
#执行数据库脚本 建表和插入数据
#spring.sql.init.mode=always 脚本执行成功后,修改为 never 避免每次运行项目都会##执行脚本覆盖数据
spring.sql.init.mode=always
lombok
@Data
功能:组合了 @Getter
、@Setter
、@ToString
、@EqualsAndHashCode
和 @NoArgsConstructor
。
@NoArgsConstructor
、@AllArgsConstructor
和 @RequiredArgsConstructor
功能:自动生成构造函数。
-
@NoArgsConstructor
:生成无参构造函数。 -
@AllArgsConstructor
:生成包含所有字段的构造函数。 -
@RequiredArgsConstructor
:生成包含所有final
字段和@NonNull
字段的构造函数。 -
@Getter
和@Setter
功能:自动生成类的 getter 和 setter 方法。
@Getter
:为类的字段生成 getter 方法。@Setter
:为类的字段生成 setter 方法
lombok 生效
-
安装Lombok插件
-
设置开启
-
依赖添加Lombok
JdbcTemplate 访问 MySQL
项目中依赖了 spring-jdbc 6.0.3,JdbcTemplate 对象会自动创建好。把 JdbcTemplate 对象注入给你的 Bean, 再调用 JdbcTemplate 的方法执行查询,更新,删除的 SQL。
JdbcTemplate 上手快,功能非常强大。提供了丰富、实用的方法,归纳起来主要有以下几种类型的方法:
(1)execute 方法:可以用于执行任何 SQL 语句,常用来执行 DDL 语句。
2)update、batchUpdate 方法:用于执行新增、修改与删除等语句。
3)query 和 queryForXXX 方法:用于执行查询相关的语句。
4)call 方法:用于执行数据库存储过程和函数相关的语句
查询
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.datasource.url=jdbc:mysql://localhost:3306/blog?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
#spring.datasource.username=root
#spring.datasource.password=123456
#配置数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/school?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=yanyu666
#执行数据库脚本 建表和插入数据
#spring.sql.init.mode=always 脚本执行成功后,修改为 never 避免每次运行项目都会执行脚本覆盖数据
spring.sql.init.mode=never
package com.yanyu.jdbc1.model;
import lombok.Data;
/**
* @Author yanyu666_508200729@qq.com
* @Date 2025/3/29 22:45
* @description:
*/
@Data
/*功能:组合了 @Getter、@Setter、@ToString、@EqualsAndHashCode 和 @NoArgsConstructor。
* */
public class UserPO {
private Integer id;
private String name;
private String password;
private String major;
}
package com.yanyu.jdbc1;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
@SpringBootTest
class Jdbc1ApplicationTests {
@Test
void contextLoads() {
}
//注入JdbcTemplate
@Autowired
JdbcTemplate jdbcTemplate;
@Test
void test1(){
String sql = "select count(*) as count from student";
Long l = jdbcTemplate.queryForObject(sql, Long.class);
System.out.println("学生总数:" + l);// 2
}
}
查询单行数据
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.datasource.url=jdbc:mysql://localhost:3306/blog?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
#spring.datasource.username=root
#spring.datasource.password=123456
#配置数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/school?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=yanyu666
#执行数据库脚本 建表和插入数据
#spring.sql.init.mode=always 脚本执行成功后,修改为 never 避免每次运行项目都会执行脚本覆盖数据
spring.sql.init.mode=never
package com.yanyu.jdbc1.model;
import lombok.Data;
/**
* @Author yanyu666_508200729@qq.com
* @Date 2025/3/29 22:45
* @description:
*/
@Data
/*功能:组合了 @Getter、@Setter、@ToString、@EqualsAndHashCode 和 @NoArgsConstructor。
* */
public class UserPO {
private Integer id;
private String name;
private String password;
private String major;
}
表名写错
// 字段 与 UserPO 进行对应的映射
//注入JdbcTemplate
@Autowired
JdbcTemplate jdbcTemplate;
@Test
void test2(){
String sql = "select * from student where id = ?";
UserPO userPO = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(UserPO.class), 2);
System.out.println(userPO);
}
有时 @Data lombok 不好使,不好使的情况下,自己写 bean规范
自定义RowMapper
在你的代码中,->
用于定义一个 RowMapper
,这是一个函数式接口,用于将 ResultSet
的一行数据映射为一个 Java 对象。
//注入JdbcTemplate
@Autowired
JdbcTemplate jdbcTemplate;
void test4(){
String sql = "select * from student where id =1";
/*
* public interface RowMapper<T> {
@Nullable
T mapRow(ResultSet rs, int rowNum) throws SQLException;
}
* RowMapper 接口只有一个 方法,所以可以使用 lambda
* */
UserPO userPO = jdbcTemplate.queryForObject(sql,(rs,rows)->{
var id = rs.getInt("id");
var name = rs.getString("name");
var stuid = rs.getString("stuid");
var major = rs.getString("major");
return new UserPO(id,name,stuid,major);
});
System.out.println(userPO);
}
解释
(rs, rownum) ->
:这是一个 lambda 表达式,表示RowMapper
接口的实现。rs
是ResultSet
对象,表示查询结果。rownum
是当前行的行号(从 1 开始),在这个例子中没有使用。
new ArticlePO(...)
:这是 lambda 表达式的主体,表示如何将ResultSet
中的一行数据映射为一个ArticlePO
对象。
查询多行记录
视频:多行数据查询
//注入JdbcTemplate
@Autowired
JdbcTemplate jdbcTemplate;
// 多行记录
@Test
void test6(){
String sql = "select * from student order by id";
List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
// 使用 forech 和 lambda
maps.forEach(el->{
el.forEach((Field,value)->{
System.out.println("字段名字" + Field + ",列值" + value);
});
});
}
mg-eZuSdlon-1744258371805)]
查询多行记录
//注入JdbcTemplate
@Autowired
JdbcTemplate jdbcTemplate;
// 多行记录
@Test
void test6(){
String sql = "select * from student order by id";
List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
// 使用 forech 和 lambda
maps.forEach(el->{
el.forEach((Field,value)->{
System.out.println("字段名字" + Field + ",列值" + value);
});
});
}