Part08-Mybatis
Part08-Mybatis
前言
在前面我们学习MySQL数据库时,都是利用图形化客户端工具(如:idea、datagrip),来操作数据库的。
在客户端工具中,编写增删改查的SQL语句,发给MySQL数据库管理系统,由数据库管理系统执行SQL语句并返回执行结果。
增删改操作:返回受影响行数
查询操作:返回结果集(查询的结果)
我们做为后端程序开发人员,通常会使用Java程序来完成对数据库的操作。Java程序操作数据库的技术呢,有很多啊。
- JDBC:(Java DataBase Connectivity),就是使用Java语言操作关系型数据库的一套API。 【是操作数据库最为基础、底层的技术】
那现在在企业项目开发中呢,一般都会使用基于JDBC的封装的高级框架,比如:Mybatis、MybatisPlus、Hibernate、SpringDataJPA。 而这些技术,目前的市场占有份额如下图所示:

从上图中,我们也可以看到,目前最为主流的就是Mybatis,其次是MybatisPlus。
所以,在我们的课程体系中呢,这两种主流的操作数据库的框架我们都要学习。 而我们在学习这两个主流的框架之前,还需要学习一下操作数据库的基础基础 JDBC。 然后接下来,再来学习Mybatis。 而在我们后面的课程中,我们还要学习MybatisPlus框架。 那么今天呢,我们就先来学习 JDBC 和 Mybatis。
今天的课程安排
- 能够说出 JDBC 的作用 🍐
- 能够使用 JDBC 对数据库进行增删改查操作 ✏️
- 能够说出数据库连接池作用 🍐
- SpringBoot整合Mybatis入门 ✏️🍐 ❤️
- Mybatis操作curd ✏️🍐 ❤️
1. JDBC
1.1 概述和入门 🍐 ✏️
概述和入门
JDBC:(Java DataBase Connectivity),就是使用Java语言操作关系型数据库的一套API。

本质:
sun公司官方定义的一套操作所有关系型数据库的规范,即接口。
各个数据库厂商去实现这套接口,提供数据库驱动jar包。
我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
快速入门
需求: 通过JDBC程序,执行update语法,更新用户表中的数据
步骤:
- 准备工作:
- 创建项目,引入mysql的驱动、junit依赖
- 注册驱动
- 获取连接对象 Connection
- 获取SQL语句执行对象 Statement
- 执行SQL语句
- 释放资源
- 准备数据库
db86
,及数据库表user
create table user(
id int unsigned primary key auto_increment comment 'ID,主键',
username varchar(20) comment '用户名',
password varchar(32) comment '密码',
name varchar(10) comment '姓名',
age tinyint unsigned comment '年龄'
) comment '用户表';
insert into user(id, username, password, name, age) values (1, 'daqiao', '123456', '大乔', 22),
(2, 'xiaoqiao', '123456', '小乔', 18),
(3, 'diaochan', '123456', '貂蝉', 24),
(4, 'lvbu', '123456', '吕布', 28),
(5, 'zhaoyun', '12345678', '赵云', 27);
- 创建一个普通的maven项目(非springboot项目),名字可为:jdbc_maven_demo,引入mysql的驱动、junit依赖

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.3</version>
<scope>test</scope>
</dependency>
- 在
src/test
目录下创建一个包cn.yangeit.test
,并在其中创建一个测试类JDBCTest
,编写入门程序 ,具体如下:

public class JDBCTest {
/**
* 修改数据
*/
@Test
public void testUpdate() throws Exception {
//1.准备工作
//1.1 注册驱动
Class.forName("com.mysql.jdbc.Driver");
//1.2 获取连接
String url = "jdbc:mysql://localhost:3306/db86";
Connection connection = DriverManager.getConnection(url, "root", "1234");
//1.3 获取SQL语句执行对象
Statement statement = connection.createStatement();
//2.执行SQL
statement.executeUpdate("update user set password = '1234567890' where id = 1");
//3.释放资源
statement.close();
connection.close();
}
}
在上述的步骤中,注册驱动、获取链接Connection、获取SQL语句执行对象 Statement 、释放资源 这几步都是固定步骤,使用JDBC程序操作数据库时,这几步都需要做的。
- 运行单元测试,查看数据库中数据的执行结果。

查询用户名为 lvbu 密码:123456的用户信息
@Test
public void testQuery() throws Exception {
//1. 注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2. 获取链接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db86", "root", "1234");
//3. 获取数据库执行对象 Statement
Statement statement = connection.createStatement();
//4. 执行SQL
ResultSet resultSet = statement.executeQuery("select * from user where username = 'lvbu' and password = '123456'");
//5. 获取结果
while (resultSet.next()){
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
String password = resultSet.getString("password");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
System.out.println(id+" 用户名:"+ username+" 密码:"+password+" 姓名:"+name+" 年龄:"+age);
}
//6. 释放资源
statement.close();
connection.close();
}
结果如下:
4 用户名:lvbu 密码:123456 姓名:吕布 年龄:28
总结
课堂作业
- jdbc操作数据库,本质是什么?🎤
- jdbc代码和sql语句混在一起,方便维护吗?🎤
- jdbc的结果集,变成对象,变成集合逻辑繁琐吗? 🎤
2. Mybatis基础 ✏️ 🍐 ❤️
2.1 介绍Mybatis ✏️
介绍Mybatis

- MyBatis是一款优秀的 持久层 框架,用于简化JDBC的开发。
MyBatis本是 Apache的一个开源项目iBatis,2010年这个项目由apache迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
在上面我们提到了两个词:一个是持久层,另一个是框架。
- 持久层:指的是就是数据访问层(dao),是用来操作数据库的。

- 框架:是一个半成品软件,是一套可重用的、通用的、软件基础代码模型。在框架的基础上进行软件开发更加高效、规范、通用、可拓展。
Mybatis对比JDBC:

通过Mybatis就可以大大简化原生的JDBC程序的代码编写,比如 通过
select * from user
查询所有的用户数据,通过JDBC程序操作呢,需要大量的代码实现,而如果通过Mybatis实现相同的功能,只需要简单的三四行就可以搞定。
代码操作
1. 创建springboot工程
创建springboot工程(如springboot_mybatis_quickstart),建议使用maven方式

2. 项目工程创建完成后,自动在pom.xml文件中,导入Mybatis依赖和MySQL驱动依赖
<?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>
<!-- 如果安装的是1.8 就改成1.8 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.yangeit</groupId>
<artifactId>springboot_mybatis_quickstart</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- web的开发的starter依赖,包含tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 单元测试starter依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--可以免除getset方法的书写-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<!--工具类-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.27</version>
</dependency>
<!-- Mybatis的起步依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<!--作用: 项目打包时,把需要的各种依赖包都打到jar包中,jar包可以独立运行,使用“java -jar”可以直接运行-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.4</version>
</plugin>
</plugins>
</build>
</project>
3. 数据准备
创建用户表user,并创建对应的实体类User。
- 用户表(如果已经存在,就不用创建了)
create table user(
id int unsigned primary key auto_increment comment 'ID,主键',
username varchar(20) comment '用户名',
password varchar(32) comment '密码',
name varchar(10) comment '姓名',
age tinyint unsigned comment '年龄'
) comment '用户表';
insert into user(id, username, password, name, age) values
(1, 'daqiao', '123456', '大乔', 22),
(2, 'xiaoqiao', '123456', '小乔', 18),
(3, 'diaochan', '123456', '貂蝉', 24),
(4, 'lvbu', '123456', '吕布', 28),
(5, 'zhaoyun', '12345678', '赵云', 27);

4. 实体类:实体类的属性名与表中的字段名一一对应。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id; //ID
private String username; //用户名
private String password; //密码
private String name; //姓名
private Integer age; //年龄
}
项目创建后的效果图:

此时不要运行,因为没有配置数据库链接信息,会报错!
1️⃣ 1. 配置Mybatis
- 在
application.yml
中配置数据库的连接信息。
spring:
datasource:
# 驱动
driver-class-name: com.mysql.jdbc.Driver
# 数据库链接以及参数
url: jdbc:mysql://localhost:3306/数据库名字?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&useSSL=false
# 用户名
username: root
# 数据库密码
password: 1234
上述的配置,可以直接复制过去,不要敲错了。记得将url中的数据库名字,改成你自己的数据库名字
2️⃣ 2. 编写SQL语句
在创建出来的springboot工程中,在引导类所在包下,在创建一个包 mapper
。在 mapper
包下创建一个接口 UserMapper ,这是一个持久层接口(Mybatis的持久层接口规范一般都叫 XxxMapper)。

UserMapper的内容如下:
@Mapper
public interface UserMapper {
/**
* 查询全部
*/
@Select("select * from user")
public List<User> findAll();
}
- @Mapper注解:表示是mybatis中的Mapper接口
- 程序运行时:框架会自动生成接口的实现类对象(代理对象),并给交Spring的IOC容器管理
- @Select注解:代表的就是select查询,用于书写select查询语句
3️⃣ 3. 单元测试
在创建出来的SpringBoot工程中,在src下的test目录下,已经自动帮我们创建好了测试类 ,并且在测试类上已经添加了注解 @SpringBootTest,代表该测试类已经与SpringBoot整合。

该测试类在运行时,会自动通过引导类加载Spring的环境(IOC容器)。我们要测试那个bean对象,就可以直接通过@Autowired注解直接将其注入进行,然后就可以测试了。
测试类代码如下:
@SpringBootTest
public class MybatisTest {
@Autowired
private UserMapper userMapper;
@Test
public void testFindAll(){
List<User> userList = userMapper.findAll();
userList.forEach(user -> {
System.out.println(user);
});
}
}
运行结果:
1. 配置SQL提示
默认我们在UserMapper接口上加的 @Select
注解中编写SQL语句是没有提示的。 如果想让idea给我们提示对应的SQL语句,我们需要在IDEA中配置与MySQL数据库的链接。
默认我们在UserMapper接口上的 @Select
注解中编写SQL语句是没有提示的。如果想让idea给出提示,可以做如下配置:

配置完成之后,发现SQL语句中的关键字有提示了,但还存在不识别表名(列名)的情况:

产生原因:Idea和数据库没有建立连接,不识别表信息
解决方案:在Idea中配置MySQL数据库连接

注意:该配置的目的,仅仅是为了在编写SQL语句时,有语法提示(写错了会报错),不会影响运行,即使不配置也是可以的。在配置的时候指定连接那个数据库,如上图所示连接的就是mybatis数据库(自己的数据库名是什么就指定什么)。
2 配置Mybatis的日志输出
默认情况下,在Mybatis中,SQL语句执行时,我们并看不到SQL语句的执行日志。
加入如下阴影部分的配置,即可查看日志:
spring:
datasource:
# 驱动
driver-class-name: com.mysql.jdbc.Driver
# 数据库链接以及参数
url: jdbc:mysql://localhost:3306/db86?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&useSSL=false
# 用户名
username: root
# 数据库密码
password: 1234
# mybatis的配置
mybatis:
configuration:
# 标准日志输出
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
打开上述开关之后,再次运行单元测试,就可以看到控制台输出的SQL语句是什么样子的。

总结
课堂作业
- 参考上述步骤,完成MyBatis的入门案例!和日志输出🎤
2.2 JDBC VS Mybatis 🍐
JDBC VS Mybatis
JDBC程序的缺点:
- url、username、password 等相关参数全部硬编码在java代码中。
- 查询结果的解析、封装比较繁琐。
- 每一次操作数据库之前,先获取连接,操作完毕之后,关闭连接。 频繁的获取连接、释放连接造成资源浪费。
分析了JDBC的缺点之后,我们再来看一下在mybatis中,是如何解决这些问题的:
数据库连接四要素(驱动、链接、用户名、密码),都配置在springboot默认的配置文件 application.properties中
查询结果的解析及封装,由mybatis自动完成映射封装,我们无需关注
在mybatis中使用了数据库连接池技术,从而避免了频繁的创建连接、销毁连接而带来的资源浪费。
使用SpringBoot+Mybatis的方式操作数据库,能够提升开发效率、降低资源浪费
而对于Mybatis来说,我们在开发持久层程序操作数据库时,需要重点关注以下两个方面:
- application.yml 配置文件中的数据源链接信息
spring:
datasource:
# 驱动
driver-class-name: com.mysql.jdbc.Driver
# 数据库链接以及参数
url: jdbc:mysql://localhost:3306/db86?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&useSSL=false
# 用户名
username: root
# 数据库密码
password: 1234
- Mapper接口(编写SQL语句)
@Mapper
public interface UserMapper {
@Select("select * from user")
public List<User> list();
}
总结
课堂作业
- JDBC的缺点有哪些?🎤
2.3 数据库连接池 🍐
在前面我们所讲解的mybatis中,使用了数据库连接池技术,避免频繁的创建连接、销毁连接而带来的资源浪费。下面我们就具体的了解下数据库连接池。
数据库连接池

没有使用数据库连接池:
客户端执行SQL语句:要先创建一个新的连接对象,然后执行SQL语句,SQL语句执行后又需要关闭连接对象从而释放资源,每次执行SQL时都需要创建连接、销毁链接,这种频繁的重复创建销毁的过程是比较耗费计算机的性能 。数据库连接池是个容器,负责分配、管理数据库连接(Connection)

程序在启动时,会在数据库连接池(容器)中,创建一定数量的Connection对象,允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
客户端在执行SQL时,先从连接池中获取一个Connection对象,然后在执行SQL语句,SQL语句执行完之后,释放Connection时就会把Connection对象归还给连接池(Connection对象可以复用),释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏
客户端获取到Connection对象了,但是Connection对象并没有去访问数据库(处于空闲),数据库连接池发现Connection对象的空闲时间 > 连接池中预设的最大空闲时间,此时数据库连接池就会自动释放掉这个连接对象
数据库连接池的好处: 👍
- 资源重用
- 提升系统响应速度
- 避免数据库连接遗漏
要怎么样实现数据库连接池呢?
官方(sun)提供了数据库连接池标准(javax.sql.DataSource接口)
- 功能:获取连接
- 第三方组织必须按照DataSource接口实现
常见的数据库连接池:
- C3P0
- DBCP
- Druid
- Hikari (springboot默认)
现在使用更多的是:Hikari、Druid (性能更优越)
代码操作
1). Hikari(追光者) [默认的连接池]

2). Druid(德鲁伊)
- Druid连接池是阿里巴巴开源的数据库连接池项目
- 功能强大,性能优秀,是Java语言最好的数据库连接池之一
如果我们想把默认的数据库连接池切换为Druid数据库连接池,只需要完成以下两步操作即可:
参考官方地址:https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter
1. 在pom.xml文件中引入依赖
<dependency>
<!-- Druid连接池依赖 -->
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.19</version>
</dependency>
2. 在application.yml中引入数据库连接配置

运行截图:

总结
课堂作业
- :microphon数据库连接池有什么好处?如果不配置,会使用连接池吗?
2.4 参数占位符
参数占位符
在Mybatis中提供的参数占位符有两种:${...}
、#{...}
#{...}
安全,常用- 执行SQL时,会将
#{…}
替换为?,生成预编译SQL,会自动设置参数值 - 使用时机:参数传递,都使用
#{…}
- 执行SQL时,会将
${...}
有危险,慎用- 拼接SQL。直接将参数拼接在简单实用SQL语句中,存在SQL注入问题
- 使用时机:如果对表名、列表进行动态设置时使用
注意事项:在项目开发中,建议使用
#{...}
,生成预编译SQL,防止SQL注入安全。
代码操作
需求1:查询id为1的 用户信息
UserMapper接口
/*
mybatis的传值:
参数占位符:#{参数}
查询id的用户
*/
@Select("select * from user where id = #{id}")
public User getUserById(Integer id);
需求2:查询年龄在[19,20)
之间的用户信息
/*
查询年龄在开始年龄 到结束年龄的用户信息
*/
@Select("select * from user where age between #{startage} and #{endAge}")
public List<User> findAllByAge(String startage,String endAge);
测试类:
@Test
public void testGetUserById(){
User userById = userMapper.getUserById(3);
System.out.println(userById);
//User(id=3, username=diaochan, password=123456, name=貂蝉, age=24)
User user2 = userMapper.getUserById(222222);
System.out.println(user2);
//null
}
@Test
public void testFindAllByAge(){
List<User> allByAge = userMapper.findAllByAge("19", "27");
System.out.println(allByAge);
}
运行结果:

注意:
1). 如果我们在定义SQL语句的时候,使用的是 #{...}

我们看到,最终生成的SQL语句是预编译的SQL语句。
2). 如果我们在定义SQL语句的时候,使用的是 ${...}

总结
课堂作业
${...}
、#{...}
的区别是什么?🎤
在mybatis的mapper接口中,我们定义SQL语句,参数占位符可以使用 #{...}
与 ${...}
,那具体什么区别呢?
符号 | 说明 | 场景 | 优缺点 |
---|---|---|---|
#{…} | 执行时,会将#{…} 替换为? ,生成预编译SQL,并自动设置参数值 | 参数值传递 | 安全、性能高 (推荐) |
${…} | 拼接SQL。直接将参数拼接在SQL语句中,存在SQL注入问题 | 表名、字段名动态设置时使用 | 不安全、性能低 |
2.5 Mybatis的XML配置文件 ✏️ 🍐 ❤️
Mybatis的开发有两种方式:
- 注解
- XML
Mybatis的XML配置文件
1. XML配置文件规范
使用Mybatis的注解方式,主要是来完成一些简单的增删改查功能。
如果需要实现复杂的SQL功能,建议使用XML来配置映射语句,也就是将SQL语句写在XML配置文件中。
在Mybatis中使用XML映射文件方式开发,需要符合一定的规范:非常重要
XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)
XML映射文件的namespace属性为Mapper接口全限定名一致
XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致。
<select>
标签:就是用于编写select查询语句的。resultType属性,指的是查询返回的单条记录所封装的类型。
代码操作
第1步:创建XML映射文件


在resources下创建同名目录,注意不是使用
.
而是使用/
第2步:编写XML映射文件
xml映射文件中的dtd约束,直接从mybatis官网复制即可
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">
</mapper>

第3步:配置
a. XML映射文件的namespace属性为Mapper接口全限定名
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.yangeit.mapper.UserMapper">
</mapper>
b. XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.yangeit.mapper.UserMapper">
<!--查询操作-->
<select id="findAll" resultType="cn.yangeit.pojo.User">
select * from user
</select>
</mapper>

运行测试类,执行结果:


3 MybatisX的使用
MybatisX是一款基于IDEA的快速开发Mybatis的插件,为效率而生。
MybatisX的安装:

可以通过MybatisX快速定位:

MybatisX的使用在后续学习中会继续分享
学习了Mybatis中XML配置文件的开发方式了,大家可能会存在一个疑问:到底是使用注解方式开发还是使用XML方式开发?
官方说明:https://mybatis.net.cn/getting-started.html
image-20220901173948645
结论: 使用Mybatis的注解,主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能,建议使用XML来配置映射语句。
总结
课堂作业
- 实际开发中使用注解还是xml文件映射,为什么?🎤
- 在Mybatis中使用XML映射文件方式开发,需要符合一定的规范,是哪些规范?
3. 管理系统升级 ✏️
3.1 部门列表查询
部门列表查询
需求:查询数据库表中的所有部门数据,展示在页面上。

代码操作
准备数据库表 dept 及 实体类 Dept
-- 部门管理 create table dept( id int unsigned primary key auto_increment comment '主键ID', name varchar(10) not null unique comment '部门名称', create_time datetime comment '创建时间', update_time datetime comment '修改时间' ) comment '部门表'; INSERT INTO `dept` VALUES (1,'学工部','2023-09-25 09:47:40','2023-09-25 09:47:40'), (2,'教研部','2023-09-25 09:47:40','2023-09-25 09:47:40'), (3,'咨询部','2023-09-25 09:47:40','2023-09-25 09:47:40'), (4,'就业部','2023-09-25 09:47:40','2023-09-25 09:47:40'), (5,'人事部','2023-09-25 09:47:40','2023-09-25 09:47:40'), (6,'行政部','2023-09-27 14:00:00','2023-09-27 14:00:00'), (7,'综合部','2023-09-25 14:44:19','2023-09-25 14:44:19');
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.time.LocalDateTime; @Data @NoArgsConstructor @AllArgsConstructor public class Dept { private Integer id; private String name; private LocalDateTime createTime; private LocalDateTime updateTime; }
在项目中引入Mybatis的起步依赖,mysql的驱动包
<!-- Mybatis的起步依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<scope>runtime</scope>
</dependency>
- 在项目的application.yml 中引入Mybatis的配置信息 (数据库连接、日志输出)
spring:
datasource:
# 驱动
driver-class-name: com.mysql.jdbc.Driver
# 数据库链接以及参数
url: jdbc:mysql://localhost:3306/db86?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&useSSL=false
# 用户名
username: root
# 数据库密码
password: 1234
type: com.alibaba.druid.pool.DruidDataSource
# mybatis的配置
mybatis:
configuration:
# 标准日志输出
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
定义mapper包,并且定义DeptMapper接口,并声明接口方法。
import com.itheima.pojo.Dept; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import java.util.List; @Mapper public interface DeptMapper { @Select("select * from dept") public List<Dept> findAll(); }
改造之前编写的dao、service的代码,在service实现中注入mapper接口
dao层的代码不需要了(备份之后,可以删除)
service层的代码,需要注入Mapper接口,调用mapper接口方法查询数据库中的数据
@Service public class DeptServiceImpl implements DeptService { @Autowired private DeptMapper deptMapper; @Override public List<Dept> queryDeptList() { return deptMapper.findAll(); } }
启动服务,打开apifox进行测试
image-20231130192402337

经过测试,我们发现,创建时间 createTime,修改时间 updateTime 属性并未成功封装。 接下来,我们就需要来处理数据封装问题。
3.2 数据封装
数据封装
我们看到查询返回的结果中大部分字段是有值的,但是createTime,updateTime这两个字段是没有值的,而数据库中是有对应的字段值的,这是为什么呢?

原因如下:
- 实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装。
- 如果实体类属性名和数据库表查询返回的字段名不一致,不能自动封装。
解决方案:
- 起别名
- 结果映射
- 开启驼峰命名
代码操作
1. 起别名:在SQL语句中,对不一样的列名起别名,别名和实体类属性名一样
@Select("select id, name, create_time createTime, update_time updateTime from dept")
public List<Dept> findAll();
2. 开启驼峰命名(推荐):如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射
驼峰命名规则: abc_xyz => abcXyz
- 表中字段名:abc_xyz
- 类中属性名:abcXyz
# mybatis的配置
mybatis:
configuration:
# 标准日志输出
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 开启驼峰命名
map-underscore-to-camel-case: true
要使用驼峰命名前提是 实体类的属性 与 数据库表中的字段名严格遵守驼峰命名。
3.3 删除部门
删除部门
删除部门数据。在点击 "删除" 按钮,会根据ID删除部门数据。

了解了需求之后,我们再看看接口文档中,关于删除部门的接口的描述,然后根据接口文档进行服务端接口的开发。

思路分析
明确了删除部门的需求之后,再来梳理一下实现该功能时,三层架构每一层的职责:

代码操作
简单参数接收
我们看到,在controller中,需要接收前端传递的请求参数。 那接下来,我们就先来看看在服务器端的Controller程序中,如何获取这类简单参数。
具体的方案有如下三种:
方案一:通过原始的 HttpServletRequest
对象获取请求参数
/**
* 根据ID删除部门 - 简单参数接收: 方式一 (HttpServletRequest)
*/
@DeleteMapping("/depts")
public Result delete(HttpServletRequest request){
String idStr = request.getParameter("id");
int id = Integer.parseInt(idStr);
System.out.println("根据ID删除部门: " + id);
return Result.success();
}
这种方案实现较为繁琐,而且还需要进行手动类型转换。
方案二:通过Spring提供的 @RequestParam
注解,将请求参数绑定给方法形参
@DeleteMapping("/depts")
public Result delete(@RequestParam("id") Integer deptId){
System.out.println("根据ID删除部门: " + deptId);
return Result.success();
}
@RequestParam
注解的value属性,需要与前端传递的参数名保持一致 。
@RequestParam注解required属性默认为true,代表该参数必须传递,如果不传递将报错。 如果参数可选,可以将属性设置为false。
方案三:如果请求参数名与形参变量名相同,直接定义方法形参即可接收。(省略@RequestParam)
@DeleteMapping("/depts")
public Result delete(Integer id){
System.out.println("根据ID删除部门: " + deptId);
return Result.success();
}
对于以上的这三种方案呢,我们推荐第三种方案。
1. Mapper层
/**
* 根据ID删除部门数据
*
* # 符号: 占位符,会被 ?替换为预编译的SQL(推荐); 通常用于字段值的替换.
* $ 符号: 字符串拼接符号,会将参数直接拼接在SQL语句中(不推荐); 如果需要动态设置表名, 字段名时, 必须使用$符号.
*/
@Delete("delete from dept where id = #{id}")
void delete(Integer id);
如果mapper接口方法形参只有一个普通类型的参数,
#{…}
里面的属性名可以随便写,如:#{id}
、#{value}
。
对于 DML 语句来说,执行完毕,也是有返回值的,返回值代表的是增删改操作,影响的记录数,所以可以将执行 DML 语句的方法返回值设置为 Integer。 但是一般开发时,是不需要这个返回值的,所以也可以设置为void。
2. Service层
@Override
public void delete(Integer id) {
//Integer deleted = deptMapper.delete(id);
//System.out.println("删除数据的结果为: " + deleted);
deptMapper.delete(id);
}
3. Controller层
@DeleteMapping("/depts")
public Result delete(Integer id){
System.out.println("根据ID删除部门: " + id);
deptService.delete(id);
return Result.success();
}
代码编写完毕之后,我们就可以启动服务,进行测试了。

总结
课堂作业
1. @RequestParam
注解有什么作用?什么时候可以省略?🎤
3.4 新增部门
新增部门
点击 "新增部门" 的按钮之后,弹出新增部门表单,填写部门名称之后,点击确定之后,保存部门数据。

了解了需求之后,我们再看看接口文档中,关于新增部门的接口的描述,然后根据接口文档进行服务端接口的开发 。

思路说明
明确了新增部门的需求之后,再来梳理一下实现该功能时,三层架构每一层的职责:

代码操作
json参数接收
我们看到,在controller中,需要接收前端传递的请求参数。 那接下来,我们就先来看看在服务器端的Controller程序中,如何获取json格式的参数。
JSON格式的参数,通常会使用一个实体对象进行接收 。
规则:JSON数据的键名与方法形参对象的属性名相同,并需要使用
@RequestBody
注解标识。

1. Controller层
在DeptController
中增加方法add,具体代码如下:
/**
* 添加部门 - json格式参数接收
*/
@Log
@PostMapping
public Result add(@RequestBody Dept dept){
System.out.println("添加部门: " + dept);
deptService.add(dept);
return Result.success();
}
2. Service层
在DeptServiceImpl
中增加add方法,完成添加部门的操作,具体代码如下:
@Override
public void add(Dept dept) {
dept.setCreateTime(LocalDateTime.now());
dept.setUpdateTime(LocalDateTime.now());
deptMapper.add(dept);
}
3. Mapper层
在 DeptMapper
中增加方法add,完成添加部门的操作具体代码如下:
/**
* 添加部门数据 - 传递多个参数时,可以把多个参数封装到一个对象中 , 然后通过 #{属性名} 来获取对象属性
*/
@Insert("insert into dept(name, create_time, update_time) values(#{name}, #{createTime}, #{updateTime})")
void add(Dept dept);
如果在mapper接口中,需要传递多个参数,可以把多个参数封装到一个对象中。 在SQL语句中获取参数的时候,#{...}
里面写的是对象的属性名【注意是属性名,不是表的字段名 】。
代码编写完毕之后,我们就可以启动服务,进行测试了。


总结
课堂作业
@RequestBody
和@RequestParam
注解区别?🎤