这个专栏给大家介绍一下 Java 家族的核心产品 - SSM 框架
JavaEE 进阶专栏Java 语言能走到现在 , 仍然屹立不衰的原因 , 有一部分就是因为 SSM 框架的存在
接下来 , 博主会带大家了解一下 Spring、Spring Boot、Spring MVC、MyBatis 相关知识点
并且带领大家进行环境的配置 , 让大家真正用好框架、学懂框架
来上一篇文章复习一下吧
点击即可跳转到前置文章
MyBatis 是⼀款优秀的持久层框架 ,
持久层框架 : 之前的数据是未进行持久化的 , 存放在内存中的 , 现在我们把它保存下来 , 这就叫做持久化 .
它支持自定义 SQL、存储过程以及高级映射 .
MyBatis 去除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
通过 MyBatis 可以简单的通过 XML 或者注解来映射原始类型、接口 , 然后来为数据库中添加和查询记录
简单来说 , MyBatis 就是实现数据库的操作的 , 无非就是 CRUD , 他替换了 JDBC 的方式
MyBatis 是基于 JDBC 的 , 就像 Spring MVC 是基于 Servlet 一样 , 都是进行了封装 .
我们常说的 SSM , 就是这三种技术的统称 : Spring Boot、Spring MVC、MyBatis
MyBatis 的官网 : https://mybatis.org/mybatis-3/zh/index.html
对于后端程序来说 , 常见的流程如下 :
我们已经学习过 JDBC , 为什么还要学 MyBatis ?
之前学习 JDBC 分九大部 :
这些代码基本和我们的业务没多大关系 , 属于功能性代码 , 而且操作及其麻烦 , 所以我们的 MyBatis 就出现了 , MyBatis 大大简化了我们 JDBC 的代码 , 而且之前学习 JDBC 还需要考虑资源释放问题 , 在 MyBatis 里面就不需要考虑了 , 因为 MyBatis 里面内置了连接池 , 它会帮助我们去创建和维护连接 , 以及创建资源 .
我们目前的简单一点的程序基本就分为三个部分 : 一部分是应用程序 , 一部分是数据库 , 中间就是通过应用程序想要调用数据库 , 要通过 MyBatis .
MyBatis 是一个持久层框架 , 也是一个 ORM 框架 , ORM (Object Relational Mapping) 叫做对象关系映射 , 在面向对象编程思想中 , 可以理解为一张表就是一个对象 .
在 MyBatis 里面 , 就可以通过面向对象(OOP) 的思想 , 来实现增删改查
在 JDBC 里面 , 更像是面向过程编程 , 这一步写什么 , 那一步写什么 , 按照顺序一步一步去写 .
那么在面向对象编程语言当中 , 将关系型数据库中的数据与对象建立起映射关系 , 进而自动的完成数据与对象的
互相转换:
在数据库中执行以下语句
-- 创建数据库
drop database if exists mycnblog;
create database mycnblog DEFAULT CHARACTER SET utf8mb4;
-- 使用数据数据
use mycnblog;
-- 创建表[用户表]
drop table if exists userinfo;
create table userinfo (
id int primary key auto_increment,
username varchar(100) not null,
password varchar(32) not null,
photo varchar(500) default '',
createtime datetime default now(),
updatetime datetime default now(),
`state` int default 1 -- 状态信息:默认为1,代表正在登录状态
) default charset 'utf8mb4';
-- 创建文章表
drop table if exists articleinfo;
create table articleinfo (
id int primary key auto_increment,
title varchar(100) not null,
content text not null,
createtime datetime default now(),
updatetime datetime default now(),
uid int not null,
rcount int not null default 1,
`state` int default 1
) default charset 'utf8mb4';
-- 创建视频表
drop table if exists videoinfo;
create table videoinfo (
vid int primary key,
`title` varchar(250),
`url` varchar(1000),
createtime datetime default now(),
updatetime datetime default now(),
uid int
) default charset 'utf8mb4';
-- 添加一个用户信息
INSERT INTO `mycnblog`.`userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`) VALUES
(1, 'admin', 'admin', '', '2021-12-06 17:10:48', '2021-12-06 17:10:48', 1);
-- 文章添加测试数据
insert into articleinfo(title,content,uid) values('Java','Java正文',1);
-- 添加视频
insert into videoinfo(vid,title,url,uid) values(1,'java title','http://www.baidu.com',1);
我们先使用一张表即可
把这段 SQL 复制到 MySQL 里面
-- 创建数据库
drop database if exists mycnblog;
create database mycnblog DEFAULT CHARACTER SET utf8mb4;
-- 使用数据数据
use mycnblog;
-- 创建表[用户表]
drop table if exists userinfo;
create table userinfo(
id int primary key auto_increment,
username varchar(100) not null,
password varchar(32) not null,
photo varchar(500) default '',
createtime datetime default now(),
updatetime datetime default now(),
`state` int default 1 -- 状态信息:默认为1,代表正在登录状态
) default charset 'utf8mb4';
-- 添加一个用户信息
INSERT INTO `mycnblog`.`userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`) VALUES
(1, 'admin', 'admin', '', '2021-12-06 17:10:48', '2021-12-06 17:10:48', 1);
接下来的目的 , 就是通过 MyBatis 查询插入的对象并且打印出来即可
接下来测试项目是否能正常运行
接下来完成第三步 , 项目就可以正常启动了
在我们的 application.properties / application.yml 里面进行配置
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8&useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
如果使用 MySQL 是 5.x 之前的版本 , driver-class-name 就使用 “com.mysql.jdbc.Driver”,如果是大于 5.x 的版本 , 那么就使用 “com.mysql.cj.jdbc.Driver”
# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件
mybatis:
mapper-locations: classpath:mapper/**Mapper.xml
# 路由存放路径: 当前路径底下新建一个 mapper,然后里面所有的名字后缀为 Mapper.xml 的都是 MyBatis 的 xml 文件
然后在 resources 文件夹下面创建一个 mapper 路径就行
后面所有的数据库连接就都放在 mapper 文件夹下
xxxMapper.xml 里面存储的都是 SQL 操作语句
那么我们为什么要配置 MyBatis 的 xml ?
这就需要谈到我们的 MyBatis 组成了
MyBatis 是由两部分组成的
比如说我们现在有一张用户表 , 那我们就会创建一个 MyBatis 的接口 , 他里面会声明操作表的各种方法 , 比如说增删改查
但是接口只能实现声明 , 并不能具体实现 , 那么我们的具体实现就是各种 SQL 语句 , 那放在哪里呢 ? 就放在许多的 xxx.xml 文件里面
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8&useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件
mybatis:
mapper-locations: classpath:mybatis/**Mapper.xml
# 路由存放路径: 当前路径底下新建一个 mapper,然后里面所有的名字最后为 Mapper.xml 的都是 MyBatis 的 xml 文件
configuration: # 配置打印 MyBatis 执行的 SQL
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 配置打印 MyBatis 执行的 SQL
logging:
level:
com:
example:
demo: debug
之前我们的程序并未启动 , 现在我们就可以启动了
那为什么我们的 MyBatis 要这么设计 ?
✅ MyBatis 要实现增删改查 , 他就一定要去写 SQL , 写 SQL 的话就有两种选择 :
新建一个 model 包
在 model 包底下新建一个类
然后添加一个 @Data 注解 , 这样就不需要再写 Getter Setter 以及 toString 方法了
package com.example.demo.model;
import lombok.Data;
@Data
public class UserInfo {
}
接下来我们继续编写 , 一定要注意的是 : 我们的属性名要和数据库里面的字段名保持一致
package com.example.demo.model;
import lombok.Data;
import java.util.Date;
/**
* 一个普通的实体类
* 用来给 MyBatis 做数据表(UserInfo)的映射的
* 保证类属性名称和数据表的字段名完全一致
* 顺序无所谓,类名可以不一样
*/
@Data
public class UserInfo {
private int id;
private String username;
private String password;
private String photo;
private Date createtime;
private Date updatetime;
private int state;
}
那我们的 MyBatis 是由接口跟 XML 组成的 , 所以我们先来创建接口
我们新建一个 mapper 包代表数据持久层
接下来在 mapper 包下面新建接口
接下来 , 在接口里面去写函数声明
package com.example.demo.mapper;
import com.example.demo.model.UserInfo;
import java.util.List;
public interface UserMapper {
// 查询所有用户信息 , 用 List 接收
public List<UserInfo> getAll();
}
那 MyBatis 的接口能是普通的接口吗 ? 那肯定不是 , 我们还需要加一个注解 : @Mapper
package com.example.demo.mapper;
import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
// MyBatis 接口,此注解一定不能省略
@Mapper
public interface UserMapper {
// 查询所有用户信息 , 用 List 接收
public List<UserInfo> getAll();
}
为了跟上面的 java 文件夹里面的 mapper 区分开 , 我们把 application.yml 里面的 mapper 文件夹改成 mybatis
那我们就在 resources 底下新建一个 mybatis 文件夹
接下来 , 我们去写一个 xxx.mapper , 去实现 UserMapper 接口里面的方法
接下来 , 我们把这段代码复制到 UserMapper.xml 里面
这段代码无需记忆 , 需要用的时候直接复制进去即可
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">
mapper>
这段代码的意思就是将接口和 xxx.xml 关联上了 , 但是 UserMapper.xml 还没实现 UserMapper 接口里面的方法 , 所以接下来我们就去实现 getAll 的方法
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
<select id="getAll" resultType="com.example.demo.model.UserInfo">
select * from userInfo
select>
mapper>
其中 , id 就是要实现的方法名 , resultType 就是要实现的方法的返回值当中最小单位的路径
在 标签内编写 SQL 语句(可不带分号)
接下来 , 我们就去测试目前代码是否有问题 , 我们就需要学习单元测试 .
番外2 : Spring Boot 单元测试
我们数据库当中的字段名是 username
实体当中 , 我们的属性名改成 name
用单元测试运行一下
首先 , 我们还是在接口里面声明方法
package com.example.demo.mapper;
import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
// MyBatis 接口,此注解一定不能省略
@Mapper
public interface UserMapper {
// 根据用户 ID 查询用户信息
// 需要添加注解 @Param("")
// 括号里面的参数名字随便起
// 这个注解的意思是:拿到uid的参数,把他赋值到id上
public UserInfo getUserById(@Param("uid")Integer id);
}
然后我们去写 UserMapper.xml
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
<select id="getUserById" resultType="com.example.demo.model.UserInfo">
select * from userInfo where id = 1
select>
mapper>
但是要注意这里
在 MyBatis 里面 , 传参使用的是 : #{}
其实我们也可以这样思考 , 需要进行输入参数的时候 , 就用 #{} 替换
这样的话 , 我们的查询语句就变成了
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- "" 里面需要写接口的路径-->
<mapper namespace="com.example.demo.mapper.UserMapper">
<!-- 带条件的查询 -->
<select id="getUserById" resultType="com.example.demo.model.UserInfo">
select * from userInfo where id = #{id}
</select>
</mapper>
package com.example.demo.mapper;
import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest // 当前测试的上下文环境为 Spring Boot
class UserMapperTest {
// 要测试谁 , 就注入谁
@Autowired
private UserMapper userMapper;
@Test
void getUserById() {
UserInfo userInfo = userMapper.getUserById(1);
System.out.println(userInfo);
}
}
运行之后报错了 , 一般单元测试出错误了 , 基本就是 xxx.xml 的错
那是 UserMapper.xml 里面哪里出现了错误呢 ?
如果你要是记不住 #{} 里面到底填什么 , 那你就索性让 @Param(“”) 里面的参数与后面紧跟着的参数一致即可
再次运行单元测试
那我们目前传过去的 id 是 1 , 那传 2 呢 ?
传 2 的话就没找到 , 为 null
添加用户操作有两种情况 :
那我们就来实现添加用户操作吧 .
我们再继续构建一组 SQL 数据
-- 创建文章表
drop table if exists articleinfo;
create table articleinfo(
id int primary key auto_increment,
title varchar(100) not null,
content text not null,
createtime datetime default now(),
updatetime datetime default now(),
uid int not null,
rcount int not null default 1,
`state` int default 1
)default charset 'utf8mb4';
然后我们要操作 文章表 , 就需要有一个文章的实体类 , 起到一个数据载体的作用
然后填入相关字段
package com.example.demo.model;
import lombok.Data;
import java.util.Date;
/**
* 文章的实体类
*/
@Data
public class ArticleInfo {
private int id;
private String title;
private String content;
private Date createtime;
private Date updatetime;
private int uid;
private int rcount;//访问量
private int state;//状态
}
package com.example.demo.mapper;
import com.example.demo.model.ArticleInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
// 记得添加 @Mapper 注解
@Mapper
public interface ArticleInfoMapper {
// 返回值设置为int:返回受影响的行数
// 记得添加 @Param("") 注解(其实不添加也可以,但是防止线上环境出问题)
// 传的是对应要插入的用户对象
// 为了避免错误,我们前后的参数保持一致,都叫做articleInfo
public int add(@Param("articleInfo") ArticleInfo articleInfo);
}
接下来 , 我们去新建一个 ArticleInfoMapper.xml
他的前面叫什么无所谓 , 后缀必须是 Mapper.xml
还是先把我们的默认模板复制进去
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">
mapper>
然后替换掉路径
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.ArticleInfoMapper">
mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- "" 里面需要写接口的路径-->
<mapper namespace="com.example.demo.mapper.ArticleInfoMapper">
<!-- id 就是方法名 -->
<!-- insert 不用写 resultType , 因为他默认就是返回受影响的行数 -->
<insert id="add">
<!-- values 后面的参数直接写 #{要插入的属性名} 属性名!划重点,不是数据库里面的字段名 -->
insert into articleinfo(title,content,uid) values (#{title},#{content},#{uid})
</insert>
</mapper>
注意一点 : 我们这里的 #{title},#{content},#{uid} 中 , {} 里面的值不是数据库的字段名 , 而是对应的实体类当中的属性名
我们可以试验一下 , 先把实体类当中的 title 改成 t , 虽然这样的话查询的时候肯定是没有对应的字段的 , 但是插入的话不受影响
我们可以通过单元测试来查看效果
接下来编写单元测试的代码
package com.example.demo.mapper;
import com.example.demo.model.ArticleInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
// 要记得加这个注解,代表 Spring Boot 的单元测试
@SpringBootTest
class ArticleInfoMapperTest {
// 属性注入
@Autowired
private ArticleInfoMapper articleInfoMapper;
@Test
void add() {
ArticleInfo articleInfo = new ArticleInfo();
articleInfo.setT("你好 MyBatis");
articleInfo.setContent("终于见面了");
articleInfo.setUid(1);
int result = articleInfoMapper.add(articleInfo);
System.out.println("添加结果:" + result);
}
}
运行一下
那我们把 t 改回成 title ,还是报错
那这就能证明一件事了 : #{} 里面的参数跟属性名和字段名没有任何关系
我们实际上想要运行成功 , 需要把 ArticleInfoMapper 当中的 @Param(“”) 注解删掉
参数是属性的时候可以加上 @Param(“”) 注解
参数是对象的情况下 , 就不要加了
如果你非要添加这个注解的话 , 我们就需要在 ArticleInfoMapper.xml 里面通过对象.
的方式去设置
那我们再来看看我们的数据库里面添没添加成功
回到刚才的问题 : #{} 里面的参数与数据库中的字段名无关 , 拿的是实体类当中的属性名
但是大家切记 : 这种花活大家万万不可取
MyBatis ORM(对象关系模型) 框架 : 实现的功能是将数据库和程序中的类进行映射 , 进行映射就是使用程序中的对象名和数据库中的字段名做映射的 , 所以默认情况下 , 应该将类中的属性名和表中的字段名全部一一对应上 .
我想要得到添加的对象的 ID ,该怎么解决呢 ?
我们需要在 xxx.xml 里面加两个东西
首先 , 重新写一个方法 , 来实现获得自增主键对应的 ID
package com.example.demo.mapper;
import com.example.demo.model.ArticleInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
// 记得添加 @Mapper 注解
@Mapper
public interface ArticleInfoMapper {
// 返回值设置为int:返回受影响的行数
// 传的是对应要插入的用户对象
// 记得添加 @Param("") 注解(其实不添加也可以,但是防止线上环境出问题)
// 为了避免错误,我们前后的参数保持一致,都叫做articleInfo
public int add(ArticleInfo articleInfo);
// 返回自增主键对应的 id
public int addGetId(ArticleInfo articleInfo);
}
这里面的参数保持不变即可
接下来 , 在 ArticleInfoMapper.xml 里面去实现对应的 SQL 语句
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.ArticleInfoMapper">
<insert id="add">
insert into articleinfo(title,content,uid) values (#{articleinfo.title},#{articleinfo.content},#{articleinfo.uid})
insert>
<insert id="addGetId" useGeneratedKeys="true" keyProperty="id">
insert into articleinfo(title,content,uid) values (#{articleinfo.title},#{articleinfo.content},#{articleinfo.uid})
insert>
mapper>
如果数据库的字段和实体类当中的属性名不一样 , 还可以继续设置一个属性 : keyColumn
package com.example.demo.mapper;
import com.example.demo.model.ArticleInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
// 要记得加这个注解,代表 Spring Boot 的单元测试
@SpringBootTest
class ArticleInfoMapperTest {
// 属性注入
@Autowired
private ArticleInfoMapper articleInfoMapper;
@Test
void add() {
ArticleInfo articleInfo = new ArticleInfo();
articleInfo.setTitle("你好 MyBatis2");
articleInfo.setContent("终于见面了2");
articleInfo.setUid(2);
int result = articleInfoMapper.add(articleInfo);
System.out.println("添加结果:" + result);
}
@Test
void addGetId() {
ArticleInfo articleInfo = new ArticleInfo();
articleInfo.setTitle("MyBatis 实现添加用户并返回自增主键的id");
articleInfo.setContent("设置 xml 中的 useGeneratedKeys=\"true\" keyProperty=\"id\"");
articleInfo.setUid(1);
int result = articleInfoMapper.addGetId(articleInfo);//返回受影响的行数
System.out.println("添加结果:" + result +
" 自增id=" + articleInfo.getId());//这才是返回自增主键对应的id
}
}
我们直接在之前的 ArticleInfoMapper 里面实现
删除文章 , 我们只需要传过去要删除的文章 id 即可
package com.example.demo.mapper;
import com.example.demo.model.ArticleInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
// 记得添加 @Mapper 注解
@Mapper
public interface ArticleInfoMapper {
// 返回值设置为int:返回受影响的行数
// 传的是对应要插入的用户对象
// 记得添加 @Param("") 注解(其实不添加也可以,但是防止线上环境出问题)
// 为了避免错误,我们前后的参数保持一致,都叫做articleInfo
public int add(@Param("articleInfo") ArticleInfo articleInfo);
// 返回自增主键对应的 id
public int addGetId(@Param("articleInfo") ArticleInfo articleInfo);
// 删除单条数据
// 返回值代表受影响的行数
public int delById(@Param("id") Integer id);
}
声明我们已经实现了 ,接下来我们就需要去写实现了 , 继续在我们的 ArticleInfoMapper.xml 里面编写即可
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.ArticleInfoMapper">
<insert id="add">
insert into articleinfo(title,content,uid) values (#{articleInfo.title},#{articleInfo.content},#{articleInfo.uid})
insert>
<insert id="addGetId" useGeneratedKeys="true" keyProperty="id" keyColumn="">
insert into articleinfo(title,content,uid) values (#{articleInfo.title},#{articleInfo.content},#{articleInfo.uid})
insert>
<delete id="delById">
delete from articleinfo where id = #{id}
delete>
mapper>
package com.example.demo.mapper;
import com.example.demo.model.ArticleInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
// 要记得加这个注解,代表 Spring Boot 的单元测试
@SpringBootTest
class ArticleInfoMapperTest {
// 属性注入
@Autowired
private ArticleInfoMapper articleInfoMapper;
@Test
void add() {
ArticleInfo articleInfo = new ArticleInfo();
articleInfo.setTitle("你好 MyBatis2");
articleInfo.setContent("终于见面了2");
articleInfo.setUid(2);
int result = articleInfoMapper.add(articleInfo);
System.out.println("添加结果:" + result);
}
@Test
void addGetId() {
ArticleInfo articleInfo = new ArticleInfo();
articleInfo.setTitle("MyBatis 实现添加用户并返回自增主键的id");
articleInfo.setContent("设置 xml 中的 useGeneratedKeys=\"true\" keyProperty=\"id\"");
articleInfo.setUid(1);
int result = articleInfoMapper.addGetId(articleInfo);//返回受影响的行数
System.out.println("添加结果:" + result +
" 自增id=" + articleInfo.getId());//这才是返回自增主键对应的id
}
@Test
void delById() {
int result = articleInfoMapper.delById(2);
System.out.println("删除结果:" + result);
}
}
我们在删除之前先来查询一下结果
接下来 , 我们要删除 2 号文章
我们来看一下数据库 , 是否删除成功了
我们还是在 ArticleInfoMapper 里面写方法声明
package com.example.demo.mapper;
import com.example.demo.model.ArticleInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
// 记得添加 @Mapper 注解
@Mapper
public interface ArticleInfoMapper {
// 返回值设置为int:返回受影响的行数
// 传的是对应要插入的用户对象
// 记得添加 @Param("") 注解(其实不添加也可以,但是防止线上环境出问题)
// 为了避免错误,我们前后的参数保持一致,都叫做articleInfo
public int add(@Param("articleInfo") ArticleInfo articleInfo);
// 返回自增主键对应的 id
public int addGetId(@Param("articleInfo") ArticleInfo articleInfo);
// 删除单条数据
// 返回值代表受影响的行数
public int delById(@Param("id") Integer id);
// 修改标题
// 返回值代表受影响的行数
// 参数有两个
// 1. 主键id
// 2. 最终要把标题改成什么
public int updateTitle(@Param("id") Integer id,@Param("title") String title);
}
接下来去 ArticleInfoMapper.xml 里面写具体实现的代码
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.ArticleInfoMapper">
<insert id="add">
insert into articleinfo(title,content,uid) values (#{articleInfo.title},#{articleInfo.content},#{articleInfo.uid})
insert>
<insert id="addGetId" useGeneratedKeys="true" keyProperty="id" keyColumn="">
insert into articleinfo(title,content,uid) values (#{articleInfo.title},#{articleInfo.content},#{articleInfo.uid})
insert>
<delete id="delById">
delete from articleinfo where id = #{id}
delete>
<update id="updateTitle">
update articleinfo set title = #{title} where id = #{id}
update>
mapper>
package com.example.demo.mapper;
import com.example.demo.model.ArticleInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
// 要记得加这个注解,代表 Spring Boot 的单元测试
@SpringBootTest
class ArticleInfoMapperTest {
// 属性注入
@Autowired
private ArticleInfoMapper articleInfoMapper;
@Test
void add() {
ArticleInfo articleInfo = new ArticleInfo();
articleInfo.setTitle("你好 MyBatis2");
articleInfo.setContent("终于见面了2");
articleInfo.setUid(2);
int result = articleInfoMapper.add(articleInfo);
System.out.println("添加结果:" + result);
}
@Test
void addGetId() {
ArticleInfo articleInfo = new ArticleInfo();
articleInfo.setTitle("MyBatis 实现添加用户并返回自增主键的id");
articleInfo.setContent("设置 xml 中的 useGeneratedKeys=\"true\" keyProperty=\"id\"");
articleInfo.setUid(1);
int result = articleInfoMapper.addGetId(articleInfo);//返回受影响的行数
System.out.println("添加结果:" + result +
" 自增id=" + articleInfo.getId());//这才是返回自增主键对应的id
}
@Test
void delById() {
int result = articleInfoMapper.delById(3);
System.out.println("删除结果:" + result);
}
@Test
void updateTitle() {
int result = articleInfoMapper.updateTitle(1,"Hello World");
System.out.println("修改结果:" + result);
}
}
在修改之前 , 我们来看一下数据
运行一下
我们回数据库看一眼
目前我们已经完成了数据库的增删改查 ,但是要想把他完善成一个真正的项目还不够呀 , 因为我们还没添加程序的入口 , 也就是 Controller
那么接下来 ,我们就逐步完善 ,让这个项目变成真正的项目
目前为止 , 我们的数据持久层的代码已经写完了 , 接下来需要完成控制器层以及服务层
我们首先创建控制器层 - Controller
UserController.java
package com.example.demo.controller;
import com.example.demo.model.UserInfo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
// 用户的查询
@RequestMapping("/getall")
public List<UserInfo> getUsers() {
// 先让程序不报错
return null;
}
}
package com.example.demo.service;
import com.example.demo.mapper.UserMapper;
import com.example.demo.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
// 属性注入
@Autowired
private UserMapper userMapper;
public List<UserInfo> getAll() {
// 直接调用 usermapper 里面的getAll
return userMapper.getAll();
}
}
那我们回过头再来看 Controller , Controller 层调用 Service
package com.example.demo.controller;
import com.example.demo.model.UserInfo;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 用户的查询
@RequestMapping("/getall")
public List<UserInfo> getUsers() {
return userService.getAll();
}
}
现在的过程是这样
那我运行一下 , 通过 Controller 能不能得到用户信息
那这样的话 , 我们就实现了正常的交互了
到此为止 , MyBatis Part 1 就结束了 , MyBatis Part 2 很快就来喽~