JavaWeb-34-Mybatis基本操作

Mybatis基本操作

一、准备工作

1. 需求说明
  • 根据资料中提供的《tlias智能学习辅助系统》页面原型及需求,完成员工管理的需求开发。

    • 资料来源:微信公众号—>黑马程序员—>获取资源—>百度网盘下载

    image-20230914190122767


    image-20230916152227098


2. 准备数据表
-- 部门管理
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,'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());

image-20230914190645650


image-20230914190810470


3. 创建SpringBoot工程
  • 创建一个新的springboot工程,选择引入对应的起步依赖(mybatis、mysql驱动、lombok)

    image-20230914191009334


    image-20230914191402656


    image-20230914191601196


    image-20230914191658250


4. 配置application.properties
  • application.properties中引入数据库连接信息

    #驱动类名称
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    #数据库连接的url
    spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
    #用户名
    spring.datasource.username=root
    #密码
    spring.datasource.password=12345
    

    image-20230914192456976


    image-20230914192937515


5. 创建实体类
  • 创建 emp表对应的实体类 Emp(实体类属性采用驼峰命名)

    package com.app.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.time.LocalDate;
    import java.time.LocalDateTime;
    
    @Data  //综合生成:getter、setter、equals、hashcode、toString方法
    @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;           //图像
        private Short job;              //职位, 说明: 1 班主任, 2 讲师, 3 学工主管, 4 教研主管, 5 咨询师
        private LocalDate entrydate;    //入职日期
        private Integer deptId;         //部门ID
        private LocalDateTime createTime; //创建时间
        private LocalDateTime updateTime; //修改时间
    }
    

    image-20230914194357547


    image-20230914194058553


6. 准备Mapper接口
  • 准备Mapper接口 EmpMapper

    package com.app.mapper;
    
    import org.apache.ibatis.annotations.Mapper;
    
    @Mapper //作用:运行时自动创建该接口的对象(代理对象),并将该对象交个IOC容器管理
    public interface EmpMapper {
    
    }
    

    image-20230914194426981


    image-20230914194450156


二、删除

1. 需求
  • 根据主键删除数据

    image-20230916152509804


2. 分析
(1) SQL语句分析

image-20230916152837656


  • SQL:

    -- 根据主键ID删除
    delete from emp where id=17;
    

    image-20230916153129848


3.Mybatis实现
  • Mapper接口:

    package com.app.mapper;
    
    import org.apache.ibatis.annotations.Delete;
    import org.apache.ibatis.annotations.Mapper;
    
    @Mapper //作用:运行时自动创建该接口的对象(代理对象),并将该对象交个IOC容器管理
    public interface EmpMapper {
        //根据主键ID删除: #{变量名} -- 动态获取要删除的数据的主键ID
        @Delete("delete from emp where id = #{id}")
        public void deleteById(Integer id);
    }
    

  • 测试:

    package com.app;
    
    import com.app.mapper.EmpMapper;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    @SpringBootTest
    class SpringbootMybatisCrudApplicationTests {
    
        @Autowired
        private EmpMapper empMapper;
    
        @Test
        public void testDeleteById() {
            empMapper.deleteById(13);
        }
    
    }
    

    image-20230916154005082


    image-20230916154259497


4. 注意事项
(1) 参数命名
  • 如果mapper接口方法 形参只有一个普通类型的参数,#{…} 里面的属性名可以随便写,如:#{id}、#{value}。
  • 不过还是建议写与表结构字段一样,增加可读性。

(2) 返回值
  • delete语句执行完毕后,是有返回值的,这个返回值:此次操作影响的记录数。

  • Mapper接口:

    package com.app.mapper;
    
    import org.apache.ibatis.annotations.Delete;
    import org.apache.ibatis.annotations.Mapper;
    
    @Mapper //作用:运行时自动创建该接口的对象(代理对象),并将该对象交个IOC容器管理
    public interface EmpMapper {
        //根据主键ID删除: #{变量名} -- 动态获取要删除的数据的主键ID
        //(1) 无返回值(常用)
    //    @Delete("delete from emp where id = #{id}")
    //    public void deleteById(Integer id);
    
        //(2) 有返回值(了解)
        @Delete("delete from emp where id = #{id}")
        public int deleteById(Integer id);
    }
    

  • 测试:

    image-20230916155248893


image-20230916155409942


三、日志输出

1. 配置
  • 可以在application.properties中,配置mybatis的日志,并指定输出到控制台。

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

    image-20230916155959953


2. 输出日志
  • 输出日志:

    image-20230916160400157


3. 预编译SQL
(1) 介绍
  • ?:参数占位符
  • 最终在执行时,会将这条SQL语句 以及 参数16 都发送给数据库
  • 数据库在执行这条SQL语句时,会使用 传递过来的参数 来替换掉 ?,最终来删除 id=16 的员工信息

image-20230916160716526


(2) 优势
  • 为何要采用这种问号占位符的预编译SQL语句?而不是直接将参数拼接在SQL语句中?

    • 优势

      ①. 性能更高

      ②. 更安全(防止SQL注入)


(3) SQL执行流程
  • SQL语句执行流程:

    • 在Java项目中,编写了一条SQL语句,要想执行,需要连接上数据库,然后将SQL语句发送给MySQL数据库服务器

    • 而这条SQL语句发送给MySQL数据库服务器之后,数据库并不是立即来执行的,而是要经历一系列的过程:

      image-20230916161509398


    • 为了提高效率,在数据库中会将优化编译后的SQL缓存起来:

      image-20230916161612464


    • 缓存的目的:

      • 下一次再执行SQL语句时会先检查缓存中是否有编译好的SQL语句,如果有就不需要再执行这一系列的操作了,可以直接去执行SQL语句。
      • 否则,又需要执行这一系列的操作,再把编译后的SQL语句缓存起来。

(4) 优势解释
① 性能更高:
  • 非预编译SQL语句:

    • 因为这三条sql语句的id的值不一样,因此每执行一条SQL语句,都要进行一系列的操作,总共要进行3次编译

    image-20230916162059926


  • 预编译SQL语句:

    • 因为使用了 ? 符号来进行占位,这样只需要编译1次,之后的执行,只需要将 参数 与 占位符 进行替换之后即可执行。
    • 这样就不用每次执行都要进行一系列的操作了,性能大大提高。

    image-20230916162622424


② 更安全(防止SQL注入)

4. 参数占位符(面试)
(1) #{…}
  • 执行SQL时,会将 #{…} 替换为 ?,生成预编译SQL,会自动设置参数值。

    image-20230916164655498


  • 使用时机:参数传递,都使用 #{…}

(2) ${…}
  • 拼接SQL。直接将参数拼接在SQL语句中,存在SQL注入问题。

    image-20230916164741670


  • 使用时机:如果对表名、列表进行动态设置时使用。

四、新增

1. 需求
  • 插入数据

    image-20230916170607682


2. 分析
(1) 字段分析
  • 新增员工信息时,哪些字段需要插入,哪些字段不需要:

    image-20230916172243336


(2) SQL语句分析
  • SQL语句:

    -- 插入数据(新增员工)
    insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)
            values ('Tony','托尼',1,'Tony.jpg',3,'2004-09-01',2,now(),now());
    

    image-20230916172616646


3. Mybatis实现
  • Mapper接口:

    package com.app.mapper;
    
    import com.app.pojo.Emp;
    import org.apache.ibatis.annotations.Delete;
    import org.apache.ibatis.annotations.Insert;
    import org.apache.ibatis.annotations.Mapper;
    
    @Mapper //作用:运行时自动创建该接口的对象(代理对象),并将该对象交个IOC容器管理
    public interface EmpMapper {
        //根据主键ID删除: #{变量名} -- 动态获取要删除的数据的主键ID
    //    (1) 无返回值(常用)
        @Delete("delete from emp where id = ${id}")
        public void deleteById(Integer id);
    
        //(2) 有返回值(了解)
    //    @Delete("delete from emp where id = #{id}")
    //    public int deleteById(Integer id);
    
        //新增员工
        @Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)" +
                //" values ('Tony','托尼',1,'Tony.jpg',3,'2004-09-01',2,now(),now())") //死编码
                " values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
        public void insertEmp(Emp emp);
    }
    

    image-20230916204831456


  • 测试:

    image-20230916205644864


    image-20230916205724350


五、主键返回

1. 需求
  • 在数据添加成功后,需要获取插入数据库数据的主键。
  • 如:添加套餐数据时,还需要维护套餐菜品关系表数据。

image-20230916211507002


2. 实现

image-20230916212104456


package com.app.mapper;

import com.app.pojo.Emp;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;

@Mapper //作用:运行时自动创建该接口的对象(代理对象),并将该对象交个IOC容器管理
public interface EmpMapper {
    //根据主键ID删除: #{变量名} -- 动态获取要删除的数据的主键ID
//    (1) 无返回值(常用)
    @Delete("delete from emp where id = ${id}")
    public void deleteById(Integer id);

    //(2) 有返回值(了解)
//    @Delete("delete from emp where id = #{id}")
//    public int deleteById(Integer id);

    //新增员工
    @Options(keyProperty = "id", useGeneratedKeys = true) //会自动将生成的主键值,赋值给emp对象的id属性
    @Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)" +
            //" values ('Tony','托尼',1,'Tony.jpg',3,'2004-09-01',2,now(),now())") //死编码
            " values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
    public void insertEmp(Emp emp);
}

image-20230916212247160


image-20230916212308083



六、更新

1. 需求
  • 根据主键ID修改数据

    image-20230916213638298


2. 分析
(1) 字段分析
  • 修改员工信息时,哪些字段需要修改,哪些字段不需要:

    image-20230916215709513


(2) SQL语句分析
  • 根据主键更新数据
-- 修改数据(更新员工信息)
update emp
set username    = 'zhangfei1',
    name        = '张飞1',
    gender      = 1,
    image       = 'zhangfei1.jpg',
    job         = 3,
    entrydate   = '2005-05-05',
    dept_id     = 3,
    update_time = now()
where id = 19;

3. Mybatis实现
  • Mapper接口:

    package com.app.mapper;
    
    import com.app.pojo.Emp;
    import org.apache.ibatis.annotations.*;
    
    @Mapper //作用:运行时自动创建该接口的对象(代理对象),并将该对象交个IOC容器管理
    public interface EmpMapper {
        //根据主键ID删除: #{变量名} -- 动态获取要删除的数据的主键ID
    //    (1) 无返回值(常用)
        @Delete("delete from emp where id = #{id}")
        public void deleteById(Integer id);
    
        //(2) 有返回值(了解)
    //    @Delete("delete from emp where id = #{id}")
    //    public int deleteById(Integer id);
    
    
    
        //新增员工信息
        @Options(keyProperty = "id", useGeneratedKeys = true) //会自动将生成的主键值,赋值给emp对象的id属性
        @Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)" +
                //" values ('Tony','托尼',1,'Tony.jpg',3,'2004-09-01',2,now(),now())") //死编码
                " values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
        public void insertEmp(Emp emp);
    
    
    
        //更新员工信息
        @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 updateEmp(Emp emp);
    }
    

    image-20230916220906310


  • 测试:

    image-20230916220839262


    image-20230916220957881


    image-20230916221033645


七、查询

1. 需求
  • 根据ID查询数据

    image-20230916223324453


2. 分析
  • SQL语句

    -- 根据主键ID查询
    select * from emp where id = 23;
    

3. Mybatis实现
  • Mapper接口:

    image-20230916224532050


  • 测试:

    image-20230916225229899


4. 封装问题
  • 会发现:部门ID、创建时间、修改时间,这三个字段查询不到值,都为 null

    image-20230916225450584


  • 这是Mybatis的数据封装问题

5. 数据封装
(1) 介绍
  • 实体类属性名 和 数据库表查询返回的字段名一致,mybatis会自动封装。
  • 如果实体类属性名 和 数据库表查询返回的字段名 不一致,不能自动封装。

image-20230916225645769


(2) 解决方案
① 字段起别名
  • 起别名:在SQL语句中,对不一样的列名起别名,别名和实体类属性名一样。

    image-20230916230014904


    image-20230916230138092


② 手动结果映射
  • 手动结果映射:通过 @Results及@Result 进行手动结果映射。

    image-20230916230523271


    image-20230916230605389


③ 开启驼峰命名
  • 开启驼峰命名:如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射。

    #开启驼峰命名自动映射,即从数据库字段名 a_column 映射到Java 属性名 aColumn。
    mybatis.configuration.map-underscore-to-camel-case=true
    

    image-20230916230923335


    image-20230916231000528


    image-20230916231042831


八、条件查询

1. 需求
  • 根据指定条件查询数据

    image-20230916233228441


  • 需求文档:

    image-20230916233402493


2. 分析
  • SQL语句

    -- 根据指定条件查询
    select *
    from emp
    where name like '%张%'   -- 员工姓名,支持模糊匹配
      and gender = 1        -- 性别 进行精确查询
      and entrydate between '2010-01-01' and '2020-01-01' -- 入职时间 进行范围查询
    order by update_time desc ; -- 根据最后修改时间进行倒序排序
    

3. Mybatis实现
  • Mapper接口

    image-20230916235052486


  • 测试:

    image-20230917001203811


  • 问题:

    image-20230917000517666


4. concat()函数
1. 介绍
  • 字符串拼接函数:concat()
  • 将多个字符串拼接成一个字符串。

image-20230917000342841


2. 优化
  • SQL:

    image-20230917000722167


  • Mybatis:

    • Mapper接口:

      image-20230917001012280


    • 测试:

      image-20230917001144715


    • 推荐这种方式!!

九、参数名说明

1.springBoot的1.x版本(早期)
  • 在springBoot的 1.x版本 /单独使用mybatis(早期的版本)

    • 编码时,形参列表是这样的:

      image-20230917001610890


    • 编译后的字节码文件,形参列表是这样的:

      image-20230917001639481


    • 原因:由于 在springBoot的 1.x版本 以及 单独使用mybatis 的时候,在对 Mapper接口 进行编译的过程中并不会保留方法的形参名称,最终变成 var1、var2 … 这样的。因此 #{参数名}形参列表对应不起来的

    • 因此需要加上一个注解:@Param(指定要获取的参数)

      image-20230917002052793


2. springBoot的2.x版本(目前)
  • 在springBoot的2.x版本(目前)

    • 编码时,形参列表是这样的:

      image-20230917002236164


    • 编译后的字节码文件,形参列表是这样的:

      image-20230917002328531


    • 原因:由于 在springBoot的 2.x版本,在对 Mapper接口 进行编译的过程中会保留方法的形参名称。因此 #{参数名}形参列表可以对应起来的
    • 因此不需要加上注解:@Param(指定要获取的参数)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值