Mybatis 知识总结2(基于注解的增删改查操作)

3 篇文章 0 订阅
2 篇文章 0 订阅

3.3 MyBatis 增删改查(注解方式)

  MyBatis 的增删改查是最基础最核心的功能,需要重点掌握。

需求说明

  对员工信息进行增删改查操作。

  • 查询(查询结果分页展示后续实现)
    • 根据主键ID查询
    • 根据条件查询
  • 新增
  • 更新
  • 删除
    • 根据主键 ID 删除
    • 根据主键 ID 批量删除
准备工作
  • 准备数据库表 dept 部门表emp 员工表并插入数据
-- 部门表
create table dept(
    id int unsigned primary key auto_increment comment '主键ID',
    name varchar(10) not null unique comment '部门名称',
    create_time datetime not null comment '创建时间',
    update_time datetime not null comment '修改时间'
) comment '部门表';
-- 插入部门表数据
insert into dept (id,name,create_time,update_time) values 
		(1,'学工部',now(),now()),
		(2,'教研部',now(),now()),
		(3,'咨询部',now(),now()),
		(4,'就业部',now(),now()),
		(5,'人事部',now(),now());
-- 员工表
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,'zhansan','123456','张三',1,'1.jpg',4,'2000-01-01',2,now(),now()),
		(2,'lisi','123456','李四',1,'2.jpg',2,'2015-01-01',2,now(),now()),
		(3,'wangwu','123456','王五',1,'3.jpg',4,'2008-01-01',2,now(),now()),
		(4,'wangmazi','123456','王麻子',1,'4.jpg',1,'2000-01-01',2,now(),now()),
		(5,'xiaohong','123456','小红',2,'5.jpg',5,'2009-01-01',3,now(),now());		
  • 创建一个新的 springboot 工程,选择引入对应的起步依赖(mybatis、mysql驱动、lombok)
1 2 3
  • Application.properties 配置文件中引入数据库连接信息 src/main/resources/application.properties
# 1 驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 2 数据库连接的 url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
# 3 连接数据库的用户名
spring.datasource.username=root
# 4 链接数据库的密码
spring.datasource.password=xxxx
  • 创建对应的实体类 Emp(实体类属性采用驼峰命名)src/main/java/com/ganming/pojp/Emp.java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
    private Integer id;             // ID
    private String username;        // 用户名
    private String password;        // 密码
    private String name;            // 姓名
    private Short gender;           // 性别,说明:1 男,2 女
    private String image;           // 图像url
    private Short job;              // 职位,说明:1 班主任,2 讲师,3 学工主管,4 教研主管,5 咨询师
    private LocalDate entrydate;    // 入职日期 LocalDate:封装 年月日
    private Integer deptId;         // 部门ID
    private LocalDateTime createTime;   // 创建时间 LocalDateTime:封装 元月日时分秒
    private LocalDateTime updateTime;   // 修改时间
}
  • 准备 Mapper 接口 EmpMapper src/main/java/com/ganming/mapper/EmpMapper.java
package com.ganming.mapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper	 // 在运行时,框架会自动的生成该接口的实现类对象(代理对象),并且将该对象交给 IOC 容器管理
public interface EmpMapper {
}
MyBatis 删除
  • 根据 ID 删除单条数据

  src/main/java/com/ganming/mapper/EmpMapper.java

// 根据 ID 删除数据
@Delete("delete from emp where id = #{id}") // 动态获取方法参数id
public void delete(Integer id);

注意事项:

  如果 mapper 接口方法形参只有一个普通类型的参数,#{…} 里面的属性名可以随便写,如:#{id}、#{value}。

  该方法如果返回值,则为该 sql 语句执行后影响的行数。

  测试根据 ID 删除数据方法:
src/test/java/com/ganming/MybatisCrudApplicationTests.java

@Resource		// 完成依赖注入
private EmpMapper empMapper;
@Test
public void testDelete(){
    empMapper.delete(5);		// 调用 EmpMapper 中的删除方法
}
  • MyBatis 配置开启日志输出

  可以在 src/main/resources/application.properties 中,打开 mybatis 的日志,并指定输出到控制台。开启后能在控制台输出预编译 SQL。

# 指定 mybatis 输出日志的位置,输出控制台
mybatis.configuration.log-impl = org.apache.ibatis.logging.stdout.StdOutImpl
mybatis日志输出

  预编译 SQL :①性能更高;②更安全(防止 SQL 注入)

性能更高

  SQL 注入:是指通过操作输入的数据来修改事先定义好的 SQL 语句,以达到执行代码对服务器进行攻击的方法。

MyBatis 参数占位符:

  #{…}:①执行 SQL 时,会将 #{…} 替换为 ?,生成预编译 SQL,会自动设置参数值。②使用时机:参数传递都使用 #{…};

  ${…}:①拼接 SQL 。直接将参数拼接在 SQL 语句中,存在 SQL 注入问题。②使用时机:如果对表名、列表名进行动态设置时使用;

#{...} ${...}
MyBatis插入

  src/main/java/com/ganming/mapper/EmpMapper.java

// 插入数据
    @Insert("insert into emp (username, name, gender, image, job, entrydate, dept_id, create_time, update_time)" +
            "value (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime});")
    public void insert(Emp emp);	// 用一个实体类来封装多个参数
性能更高

  src/test/java/com/ganming/MybatisCrudApplicationTests.java

@Test
public void testInsert(){
    Emp emp = new Emp();
    emp.setUsername("zhouzhiruo");
    emp.setName("周芷若");
    emp.setImage("z.jpg");
    emp.setGender((short)2);
    emp.setJob((short)1);
    emp.setEntrydate(LocalDate.of(2002,2,23));
    emp.setCreateTime(LocalDateTime.now());
    emp.setUpdateTime(LocalDateTime.now());
    emp.setDeptId(1);
    empMapper.insert(emp);
}
  • 新增(主键返回)

  如上,我们新增一个 emp 员工数据时,主键 id 是自增产生的,我们并没有传值,但是当程序中需要这个主键时(需要往其他表插入相关信息),我们该如何获取呢?

  如果直接获取 emp 的 id,将得到的是 null,如下:默认情况下,主键值是不返回的。

性能更高 性能更高

  如需返回,可在该方法上添加 @Options 注解

  useGeneratedKeys = true :表示我们需要拿到生成的主键值。

  keyProperty = "id" : 表示我们所获取到的主键赋值给 emp 对象的 id 属性上。

性能更高
MyBatis更新

  更新一般要根据一条数据的唯一键来更新其他字段,所以更新方法需要传递更新哪条数据的哪些字段值。

  src/main/java/com/ganming/mapper/EmpMapper.java

// 修改数据
@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);

  src/test/java/com/ganming/MybatisCrudApplicationTests.java

@Test
public void testUpdate(){
    Emp emp = new Emp();
    emp.setId(1);			// 跟新第一条数据
    emp.setUsername("zhaoming");
    emp.setName("赵敏");
    emp.setImage("z.jpg");
    emp.setGender((short)2);
    emp.setJob((short)1);
    emp.setEntrydate(LocalDate.of(2002,2,23));
    //emp.setCreateTime(LocalDateTime.now());	// 创建时间不需要更新了
    emp.setUpdateTime(LocalDateTime.now());		// 每次更新都需要修改更新时间
    emp.setDeptId(1);
    empMapper.update(emp);
}
MyBatis查询

  查询是有查询结果的,必须要有返回值,需要封装到实体类中,如果查出来是一条,就直接返回对应的实体类,如果查询结果是多条,就封装到实体类的集合或数组中。

  • 根据 id 查询:根据 id 在本例中只能查到一条数据,所以设置返回结果为 Emp 类型即可。

  src/main/java/com/ganming/mapper/EmpMapper.java

// 根据id查询
@Select("select * from emp where id = #{id}")
public Emp selectById(Integer id);

  src/test/java/com/ganming/MybatisCrudApplicationTests.java

// 测试查询
@Test
public void testSelectById(){
    Emp emp = empMapper.selectById(1);
    System.out.println(emp);
}

  打印的查询结果如下,可发现除了deptId、createTime、updateTime 这三个属性为 null 外,其他属性都正常显示。这是因为数据表中的字段名与需要封装的实体类 Emp 的属性名这三个没有完全对应上,数据表的命名规则常采用 a_column,而实体类的属性命名规则为aColumn。

查询结果 查询结果

  MyBatis 的数据封装:实体类属性名和数据库表查询返回的字段名一致,mybatis 会自动封装;如果不一致则不会自动封装。

  • 解决方案一(了解):给数据库表查询返回的字段名取别名,让别名和实体类属性名一致即可(需要起别名就不能用 * 来输出所有字段了)
查询结果
  • 解决方案二(了解):通过 @Results@Result 注解手动映射封装
通过 @Results, @Result 注解手动映射封装

  @Results 注解传入的参数是一个 @Result 数组;

  @Result 注解传入的参数是 column(数据库表的字段)和 property(实体类的属性名),表示把column 的值映射到 property 的值上。

  • 解决方案三(推荐):开启 mybatis 的驼峰命名自动映射开关

  开关打开则下划线分割(a_column)的数据库表字段命名会自动封装到实体类中的驼峰(aColumn)命名属性当中。

  在 src/main/resources/application.properties 中开启这项配置

开启 mybatis 的驼峰命名自动映射开关
  • 按条件查询:

  根据输入的员工姓名支持模糊匹配)、性别精确查询)、入职时间范围查询)搜索满足条件的员工信息;并对查询结果根据入职时间倒序排序

按条件查询

  src/main/java/com/ganming/mapper/EmpMapper.java

// 根据条件查询
@Select("select * from emp where name like '%${name}%' and gender = #{gender} and " +
        "entrydate between #{begin} and #{end} order by entrydate desc;")
public List<Emp> list(String name,short gender,LocalDate begin,LocalDate end);

  由于 like 模糊匹配,我们需要在关键字前后拼接上 % ,所以 like 后面一定是个字符串,字符串当中是不能使用 #{} 的,所以在这里使用 ${} 进行字符串的拼接。但是这样拼接存在性能低不安全存在 SQL 注入问题。

按条件查询

  mysql 给我们提供了一个 concat 字符串拼接函数,它可以接受多个字符串参数,将它们拼接位一个字符串:

mysql的concat函数

  利用 concat 字符串拼接比 ${} 拼接更好,排除了上述问题的隐患。

按条件查询 按条件查询

  参数名说明(了解链接:视频13:50开始

参数名说明

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ItDaChuang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值