Mybatis——增删改查
基于Mybatis创建的SpringBoot,实现增删改查的基本操作,详细讲解过程,问题发现,问题分析,问题解决!
1)条件准备:构建基于Mybatis的SpringBoot项目
【1】创建SpringBoot工程
- 文件
- 新建
- 新模块
- 语言-java
- 类型-Maven
- 工件-项目名
- 选择自己版本的jdk
- 打包-默认选择jar
- 选择依赖
- 依赖①-Mybatis Framework
Mybatis Framework:Mybatis框架是一款持久层框架,它通过XML映射文件或者注解方式将Java对象和SQL语句进行映射,从而简化了Java程序访问关系型数据库的操作。
- 依赖②-MySQL Driver
MySQL Driver:MySQL Driver是MySQL数据库的Java驱动程序,它提供了Java程序与MySQL数据库之间的连接和交互能力。Java程序需要使用MySQL数据库时,需要先加载MySQL Driver,然后通过DriverManager获取数据库连接。
【2】连接数据库
连接数据库看我的这篇博文:IDEA连接MySQL数据库
【3】创建员工表emp
SQL脚本如下:
-- 员工管理
create table emp (
id int unsigned primary key auto_increment comment 'ID',
username varchar(20) not null unique comment '用户名',
password varchar(32) default '123456' comment '密码',
name varchar(10) not null comment '姓名',
gender tinyint unsigned not null comment '性别, 说明: 1 男, 2 女',
image varchar(300) comment '图像',
job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师',
entrydate date comment '入职时间',
dept_id int unsigned comment '部门ID',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间'
) comment '员工表';
INSERT INTO emp
(id, username, password, name, gender, image, job, entrydate,dept_id, create_time, update_time) VALUES
(1,'jinyong','123456','金庸',1,'1.jpg',4,'2000-01-01',2,now(),now()),
(2,'zhangwuji','123456','张无忌',1,'2.jpg',2,'2015-01-01',2,now(),now()),
(3,'yangxiao','123456','杨逍',1,'3.jpg',2,'2008-05-01',2,now(),now()),
(4,'weiyixiao','123456','韦一笑',1,'4.jpg',2,'2007-01-01',2,now(),now()),
(5,'changyuchun','123456','常遇春',1,'5.jpg',2,'2012-12-05',2,now(),now()),
(6,'xiaozhao','123456','小昭',2,'6.jpg',3,'2013-09-05',1,now(),now()),
(7,'jixiaofu','123456','纪晓芙',2,'7.jpg',1,'2005-08-01',1,now(),now()),
(8,'zhouzhiruo','123456','周芷若',2,'8.jpg',1,'2014-11-09',1,now(),now()),
(9,'dingminjun','123456','丁敏君',2,'9.jpg',1,'2011-03-11',1,now(),now()),
(10,'zhaomin','123456','赵敏',2,'10.jpg',1,'2013-09-05',1,now(),now()),
(11,'luzhangke','123456','鹿杖客',1,'11.jpg',5,'2007-02-01',3,now(),now()),
(12,'hebiweng','123456','鹤笔翁',1,'12.jpg',5,'2008-08-18',3,now(),now()),
(13,'fangdongbai','123456','方东白',1,'13.jpg',5,'2012-11-01',3,now(),now()),
(14,'zhangsanfeng','123456','张三丰',1,'14.jpg',2,'2002-08-01',2,now(),now()),
(15,'yulianzhou','123456','俞莲舟',1,'15.jpg',2,'2011-05-01',2,now(),now()),
(16,'songyuanqiao','123456','宋远桥',1,'16.jpg',2,'2010-01-01',2,now(),now()),
(17,'chenyouliang','123456','陈友谅',1,'17.jpg',NULL,'2015-03-21',NULL,now(),now());
【4】创建实体类Emp
import java.time.LocalDate;
import java.time.LocalDateTime;
public class Emp {
private Integer id;
private String username;
private String password;
private String name;
private Short gender;
private String image;
private Short job;
private LocalDate entrydate;
private Integer deptId;
private LocalDateTime createTime;
private LocalDateTime updateTime;
public Emp() {
}
public Emp(Integer id, String username, String password, String name, Short gender, String image, Short job, LocalDate entrydate, Integer deptId, LocalDateTime createTime, LocalDateTime updateTime) {
this.id = id;
this.username = username;
this.password = password;
this.name = name;
this.gender = gender;
this.image = image;
this.job = job;
this.entrydate = entrydate;
this.deptId = deptId;
this.createTime = createTime;
this.updateTime = updateTime;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Short getGender() {
return gender;
}
public void setGender(Short gender) {
this.gender = gender;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public Short getJob() {
return job;
}
public void setJob(Short job) {
this.job = job;
}
public LocalDate getEntrydate() {
return entrydate;
}
public void setEntrydate(LocalDate entrydate) {
this.entrydate = entrydate;
}
public Integer getDeptId() {
return deptId;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "Emp{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", name='" + name + '\'' +
", gender=" + gender +
", image='" + image + '\'' +
", job=" + job +
", entrydate=" + entrydate +
", deptId=" + deptId +
", createTime=" + createTime +
", updateTime=" + updateTime +
'}';
}
}
【5】项目结果
【6】前提知识点了解
参数占位符 | 【1】说明和【2】使用时机 |
---|---|
#{…} | 【1】执行SQL时,会将#{…}替换成?,生成预编译SQL,会自动设置参数值。【2】参数传递,都使用==#{…}== |
${…} | 【1】拼接SQL,直接将参数拼接在SQL语句中,存在SQL注入问题。【2】如果对表名、列表进行动态设置时使用 |
2)增加操作
- ①在Mapper接口里面定义的增加操作的方法需要用到 @Insert 注解
- ② @Insert 基本语法:@Insert(“insert into 表名(字段1,字段2…)”+“values(#{变量1},#{变量2})”)
- ③如果插入的数据数据项比较多,需要利用对象存储和对象传参
【1】在Mapper接口里面【增加数据】的方法代码
//新增数据
@Options(keyProperty = "id",useGeneratedKeys = true)//会自动将生成的主键值,赋值给emp对象的id属性
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)" +
"values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
public void insert(Emp emp);
解释部分代码:
@Options(keyProperty = "id",useGeneratedKeys = true)
这段代码使用了@Options注解,并提供了两个参数:keyProperty和useGeneratedKeys。
- keyProperty = “id”:
这个参数指定了生成的主键值要赋值给emp对象的id属性。也就是说,当插入一条记录后,自动生成的主键值将被赋值给id属性。- useGeneratedKeys = true:
这个参数表示要获取数据库自动生成的主键。当插入一条记录时,数据库会自动生成一个主键值,并将其赋值给id属性。- 综合来看,这段代码的作用是在执行数据库插入操作后,自动将数据库生成的主键值赋值给emp对象的id属性。这样,程序员就无需手动获取和设置主键值,节省了开发的时间和精力。
注意:对于自增的主键,如果只是通过emp.getId(),获取出来的值只能是 null.需要在EmpMapper接口实现方法那里加上@Option注解来获取自增的主键值。这样才能获取成功!
【2】代码测试部分:
@Test
public void testInsert(){
//构造员工对象
Emp emp=new Emp();
emp.setUsername("华1");
emp.setName("Mike");
emp.setImage("1.jpg");
emp.setGender((short)1);
emp.setJob((short)1);
emp.setEntrydate((LocalDate.of(2000,1,1)));
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
emp.setDeptId(1);
//执行新增员工信息的操作
empMapper.insert(emp);
//通过 @Options注解获取到的id,并输出验证
System.out.println(emp.getId());
}
3)删除操作
【1】在Mapper接口里面【删除数据】的方法代码
//根据id删除员工数据
@Delete("delete from emp where id=#{id}")
public int del(int id);
【2】代码测试部分:
@Test
public void testDel() {
int count = empMapper.del(17);
System.out.println(count+"记录条已删除!");
}
注意:empMapper.del()返回值是该操作影响的记录数,也就是删除了几条数据。
4)修改操作
- ①根据主键修改更新,下面以id为例子
- ② @Update基本语法@Update(“update 表名 set 待更新字段1=#{存放更新值的变量1}… where 主键字段 = #{存入的变量}”),实现动态更新数据。
- ③如果插入的数据数据项比较多,需要利用对象存储和对象传参
【1】在Mapper接口里面【修改数据】的方法代码
//根据id更新员工数据
@Update("update emp set username=#{username},name=#{name},gender=#{gender},image=#{image},"+
"job=#{job},entrydate=#{entrydate},dept_id=#{deptId},update_time=#{updateTime} where id = #{id}")
public void update(Emp emp);
【2】代码测试部分:
@Test
public void testUpdate(){
//构造员工对象
Emp emp=new Emp();
emp.setId(18);//要更新的是ID为18的员工数据
//要更新的数据项
emp.setUsername("华");
emp.setName("汤姆1");
emp.setImage("2.jpg");
emp.setGender((short)1);
emp.setJob(((short)2));
emp.setEntrydate((LocalDate.of(2000,1,1)));
emp.setUpdateTime(LocalDateTime.now());//更新的时间
emp.setDeptId(1);
//执行新增员工信息的操作
empMapper.update(emp);
}
5)查找操作
(1)基本查询
【1】在Mapper接口里面【查找数据】的方法代码
//根据id查询员工数据
@Select("select * from emp where id=#{id}")
public Emp getById(Integer id);//把查询的结果封装到emp对象中再返回
【2】代码测试部分:
@Test
public void testGetById(){
Emp emp=empMapper.getById(22);//查询id为22的员工数据
System.out.println(emp);
}
【3】查询结果
【4】结果分析
问题:为什么最后的三个字段查询出来的值是null?
分析:
- ①实体类属性名 和 数据库表查询返回的字段名一致,mybatis会自动封装
- ②如果实体类属性名 和 数据库表查询返回的字段名不一致,不能自动封装
【5】解决方案
- 方案一,给字段起别名,让别名和实体类属性一致
修改在Mapper接口里面【查找数据】的方法代码
@Select("select id, username, password, name, gender, image, job, entrydate, "+
"dept_id as deptId, create_time as reateTime , update_time as updateTime from emp where id=#{id}")
public Emp getById(Integer id);//把查询的结果封装到emp对象中再返回
测试成功!
- 通过@Results,@Result注解手动映射封装【比较繁琐,了解】
修改在Mapper接口里面【查找数据】的方法代码
//方案二,通过@Results,@Result注解手动映射封装
@Results({
@Result(column = "dept_id",property = "deptId"),
@Result(column = "create_time",property = "createTime"),
@Result(column = "update_time",property = "updateTime"),
})
@Select("select * from emp where id=#{id}")
public Emp getById(Integer id);//把查询的结果封装到emp对象中再返回
测试成功!
- #开启Mybatis的驼峰命名自动映射的开关【推荐】
在application.properties配置文件中,添加以下代码。使用之间的在Mapper接口里面【查找数据】的方法代码即可。
#开启Mybatis的驼峰命名自动映射的开关
mybatis.configuration.map-underscore-to-camel-case=true
测试成功!
(2)条件查询
查询满足这三个条件的员工信息:名字带有“张”,性别是“男”,入职时间在"2010-01-01"-------“2020-01-01”
【1】在Mapper接口里面【条件查询数据】的方法代码
注意:字符串里面不能使用 #{} 的,因此要使用 $ 符号【字符串拼接符号】来代替。但是这样的话,该SQL语句就没有预编译这一步骤,可能存在SQL注入的问题。
//条件查询员工,查询的结果可能多个
@Select("select * from emp where name like '%${name}%' and gender=#{gender} and "+
"entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin,LocalDate end);
解决上述存在的SQL注入问题,利用SQL的concat拼接字符串函数。
//条件查询员工,查询的结果可能多个
@Select("select * from emp where name like concat('%',#{name},'%') and gender=#{gender} and "+
"entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin,LocalDate end);
【2】代码测试部分:
//条件查询
@Test
public void testList(){
List<Emp> empList=empMapper.list("张",(short)1,LocalDate.of(2010,1,1),LocalDate.of(2020,1,1));
System.out.println(empList);
}
【3】测试结果
使用 $ 符号的查询结果
使用 concat() 函数的查询结果
6)总结
其实创建Emp实体类不需要如此繁杂的代码,可以引入lombok依赖减少代码量,但是我引入之后就报错,如果有哪位大佬知道的嘀嘀嘀一下~~。2023版的IDEA是已经集成了lombok,并不需要下载插件,但是我引入如下就会出现不存在该依赖。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)