Mybatis学习

Mybatis学习

一、Mybatis概述

  1. MyBatis是一款优秀的 持久层 框架,用于简化JDBC的开发
  2. MyBatis本是 Apache的一个开源项目iBatis, 2010年这个项目由apache迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
  3. 官网:https://mybatis.org/mybatis-3/zh/index.html

二、Mybatis入门

2.1 使用Mybatis查询所有用户数据

  • 步骤:
    1. 准备工作(创建springboot工程,数据库表user,实体类User)
    2. 引入Mybatis相关依赖,配置Mybatis
    3. 编写SQL语句(注解/xml)

创建springboot工程和数据库表

  • springboot工程创建见前两期整理

    • 连接数据库配置文件:

      properties 复制代码
      #驱动类名称
      spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
      #数据库连接的url
      spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
      #连接数据库的用户名
      spring.datasource.username=root
      #连接数据库的密码
      spring.datasource.password=123456
  • 数据库创建

    • 创建database,命名为mybatis

    • 创建表单:

      sql 复制代码
      create table user(
          id int unsigned primary key auto_increment comment 'ID',
          name varchar(100) comment '姓名',
          age tinyint unsigned comment '年龄',
          gender tinyint unsigned comment '性别, 1:男, 2:女',
          phone varchar(11) comment '手机号'
      ) comment '用户表';
      
      insert into user(id, name, age, gender, phone) VALUES (null,'白眉鹰王',55,'1','18800000000');
      insert into user(id, name, age, gender, phone) VALUES (null,'金毛狮王',45,'1','18800000001');
      insert into user(id, name, age, gender, phone) VALUES (null,'青翼蝠王',38,'1','18800000002');
      insert into user(id, name, age, gender, phone) VALUES (null,'紫衫龙王',42,'2','18800000003');
      insert into user(id, name, age, gender, phone) VALUES (null,'光明左使',37,'1','18800000004');
      insert into user(id, name, age, gender, phone) VALUES (null,'光明右使',48,'1','18800000005');
  • 实体类创建:

    java 复制代码
    package com.itheima.pojo;
    
    public class User {
    
        private Integer id;
        private String name;
        private Short age;
        private Short gender;
        private String phone;
    
        public User() {
        }
    
        public User(Integer id, String name, Short age, Short gender, String phone) {
            this.id = id;
            this.name = name;
            this.age = age;
            this.gender = gender;
            this.phone = phone;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Short getAge() {
            return age;
        }
    
        public void setAge(Short age) {
            this.age = age;
        }
    
        public Short getGender() {
            return gender;
        }
    
        public void setGender(Short gender) {
            this.gender = gender;
        }
    
        public String getPhone() {
            return phone;
        }
    
        public void setPhone(String phone) {
            this.phone = phone;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    ", gender=" + gender +
                    ", phone='" + phone + '\'' +
                    '}';
        }
    }
  • 定义接口类

    java 复制代码
    package com.itheima.mapper;
    
    import java.util.List;
    
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Select;
    
    import com.itheima.pojo.User;
    
    @Mapper // 在运行时,会自动生成该接口的实现类对象(),并且将该对象交给IOC容器管理
    public interface UserMapper {
        // 查询全部的用户信息
        @Select("SELECT * FROM user")
        public List<User> list();
    }
  • 编写测试单元:

    java 复制代码
    package com.itheima;
    
    import java.util.List;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import com.itheima.mapper.UserMapper;
    import com.itheima.pojo.User;
    
    @SpringBootTest // springboot整合单元测试的注解
    class SpringbootMybatisQuickstartApplicationTests {
    
        @Autowired
        private UserMapper userMapper;
    
        @Test
        public void testListUser() {
            List<User> userList = userMapper.list();
            userList.stream().forEach(user -> {
                System.out.println(user);
            });
        }
    
    }

2.2 数据库连接池

  • 概念:

    • 数据库连接池是个容器,负责分配、管理数据库连接(Connection)
    • 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
    • 释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏
  • 标准接口:DataSource

    • 官方(sun)提供的数据库连接池接口,由第三方组织实现此接口。
    • 功能:获取连接
  • Druid(德鲁伊)

    • Druid连接池是阿里巴巴开源的数据库连接池项目
    • 功能强大,性能优秀,是Java语言最好的数据库连接池之一
  • 如何更换连接池:

    xml 复制代码
    <!-- pom.xml引入依赖 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.2.8</version>
    </dependency>
  • 另一种配置方式:

    properties 复制代码
    spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.druid.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
    spring.datasource.druid.username=root
    spring.datasource.druid.password=123456

2.3 lombok 工具包

  • Lombok是一个实用的Java类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化java开发、提高效率。
  • 加入lombok依赖

    properties 复制代码
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
  • 简化实体类:

    java 复制代码
    import lombok.*;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    // 最常用的三个注解
    public class User {
    
        private Integer id;
        private String name;
        private Short age;
        private Short gender;
        private String phone;
    }

三、Mybatis基础操作

3.1 工程创建准备

步骤:

  1. 创建数据库:

    • 员工表:

      mysql 复制代码
      -- 员工管理
      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());
    • 部门表:

      mysql 复制代码
      -- 部门管理
      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());
  2. 创建springboot工程,引入相关依赖:

    • Lombok
    • SQL driver
    • Mybatis Framwork
  3. 配置文件中引入数据库连接信息

    properties 复制代码
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
    spring.datasource.username=root
    spring.datasource.password=123456
  4. 创建对应的实体类Emp(实体类属性采用驼峰命名)

    java 复制代码
    package com.zcn.pojo;
    
    import java.time.LocalDate;
    import java.time.LocalDateTime;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    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;
    }
  5. 创建接口类

    java 复制代码
    package com.zcn.mapper;
    
    import org.apache.ibatis.annotations.Mapper;
    
    @Mapper
    public interface EmpMapper {
    
    }
    • 可以在接口类中,创建打印表单的sql语句用于测试

3.2 删除操作

  • sql中直接删除:

    mysql 复制代码
    -- 根据ID删除数据
    delete  from emp where id = 17;
  • 定义接口类方法

    java 复制代码
    @Delete("delete from emp where id=#{id}")  // 占位符 被?替换,生成预编译的SQL
    public void delete(Integer id);
  • 进行删除测试

    java 复制代码
    @Test
    public void testDelete() {
        empMapper.delete(17);
    }
    // 如果方法返回int类型,则代表该语句影响的数据数

预编译SQL

  • 优势:
    • 性能更高
    • 更安全(防止SQL注入)

3.3 插入操作

  • 在SQL中直接操作

    mysql 复制代码
    -- 插入数据
    insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values ('songyuanqiao','宋远桥',1,'1.jpg',2,'2012-10-09',2,NOW(),NOW);
  • 定义接口类方法

    java 复制代码
    @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);
  • 进行插入测试

    java 复制代码
    @Test
    public void testInsert() {
        Emp emp = new Emp();
        emp.setUsername("Tom");
        emp.setName("汤姆");
        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);
    }
  • 主键返回

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

    • 实现:

      java 复制代码
      @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);

3.4 更新操作

  • SQL语句

    mysql 复制代码
    update emp set username = 'songdaxia', name = '宋大侠', gender = 1 , image = '1.jpg' , job = 2, entrydate = '2012-01-01', dept_id = 2, update_time = '2022-10-01 12:12:12' where id = 19;
  • 定义接口类方法

    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);
  • 测试方法

    java 复制代码
    @Test
    public void testUpdate() {
        Emp emp = new Emp();
        emp.setId(23);
        emp.setUsername("Tom6");
        emp.setName("汤姆6");
        emp.setImage("1.jpg");
        emp.setGender((short) 1);
        emp.setJob((short) 1);
        emp.setEntrydate(LocalDate.of(2002, 2, 4));
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(1);
    
        empMapper.update(emp);
    }

3.5 查询操作

根据ID查询

  • SQL语句

    mysql 复制代码
    select *  from emp where id = 19;
  • 定义接口类方法

    java 复制代码
    @Select("select * from emp where id = #{id}")
    public Emp getById(Integer id);
  • 查询测试

    java 复制代码
    @Test
    public void testSelect() {
        Emp emp = empMapper.getById(23);
        System.out.println(emp);
    }
  • 输出

    Emp(id=23, username=Tom6, password=123456, name=汤姆6, gender=1, image=1.jpg, job=1, entrydate=2002-02-04, deptId=null, createTime=null, updateTime=null)

  • 解决方案一:给字段起别名,让别名与实体类属性一致

    java 复制代码
    @Select("select id, username, password, name, gender, image, job, entrydate, dept_id deptId, create_time createTime, update_time updateTime from emp where id = #{id} ")
    public Emp getById(Integer id);
  • 解决方案二:通过 @Results及@Result 进行手动结果映射

    java 复制代码
    @Select("select * from emp where id = #{id}")
    @Results({
            @Result(column = "dept_id", property = "deptId"),
        @Result(column = "create_time", property = "createTime"),
        @Result(column = "update_time", property = "updateTime")})
    public Emp getById(Integer id);
  • 解决方案三:开启驼峰命名,如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射

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

按条件查询

  • SQL语句

    mysql 复制代码
    select *  from emp where name like '%张%' and gender = 1 and entrydate between '2010-01-01' and '2020-01-01 ' order by update_time desc;
  • 定义接口方法

    java 复制代码
    @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);
  • 测试查询

    java 复制代码
    @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);
    }
  • 注意:springboot1.x版本/单独使用mybatis时,需要加入一个插件,否则条件参数需要加@Param注解

    properties 复制代码
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <compilerArgs>
                <arg>-parameters</arg>
            </compilerArgs>
        </configuration>
    </plugin>

四、XML映射文件

  • 规范:
    • XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)。
    • XML映射文件的namespace属性为Mapper接口全限定名一致。
    • XML映射文件中sql语句的id与Mapper 接口中的方法名一致,并保持返回类型一致。
  • 映射步骤

    1. 在resources中创建一个包 com.zcn.mapper

    2. 创建EmpMapper.xml文件

      xml 复制代码
      <?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.zcn.mapper.EmpMapper">
      
          <sql id="commonSelect">
              select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time
              from emp
          </sql>
      
         <!-- 动态更新员工-->
          <update id="update2">
              update emp
              <set>
                  <if test="username != null">username = #{username},</if>
                  <if test="name != null">name = #{name},</if>
                  <if test="gender != null">gender = #{gender},</if>
                  <if test="image != null">image = #{image},</if>
                  <if test="job != null">job = #{job},</if>
                  <if test="entrydate != null">entrydate = #{entrydate},</if>
                  <if test="deptId != null">dept_id = #{deptId},</if>
                  <if test="updateTime != null">update_time = #{updateTime}</if>
              </set>
              where id = #{id}
          </update>
      
          <!--resultType: 单条记录封装的类型-->
          <select id="list" resultType="com.zcn.pojo.Emp">
              <include refid="commonSelect"/>
              <where>
                  <if test="name != null">
                      name like concat('%', #{name}, '%')
                  </if>
                  <if test="gender != null">
                      and gender = #{gender}
                  </if>
                  <if test="begin != null and end != null">
                      and entrydate between #{begin} and #{end}
                  </if>
              </where>
              order by update_time desc
          </select>
      
          <!--批量删除员工 (18,19,20)-->
          <!--
              collection: 遍历的集合
              item: 遍历出来的元素
              separator: 分隔符
              open: 遍历开始前拼接的SQL片段
              close: 遍历结束后拼接的SQL片段
          -->
          <delete id="deleteByIds">
              delete  from emp where id in
              <foreach collection="ids" item="id" separator="," open="(" close=")">
                  #{id}
              </foreach>
          </delete>
      
      </mapper>
    3. 定义接口的方法

      java 复制代码
      public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);

五、Mybatis动态SQL

概念:随着用户的输入或外部条件的变化而变化的SQL语句,我们称为动态SQL。

动态查询

xml 复制代码
<!-- if标签 -->
<!--resultType: 单条记录封装的类型-->
<select id="list" resultType="com.zcn.pojo.Emp">
    <include refid="commonSelect"/>
    <where>
        <if test="name != null">
            name like concat('%', #{name}, '%')
        </if>
        <if test="gender != null">
            and gender = #{gender}
        </if>
        <if test="begin != null and end != null">
            and entrydate between #{begin} and #{end}
        </if>
    </where>
    order by update_time desc
</select>

动态更新员工信息,防止出现每项信息都填写(不出现null),简化过程

java 复制代码
    //动态更新员工 - 更新ID为18的员工 username 更新为 Tom111, name更新为 汤姆111, gender更新为2
    @Test
    public void testUpdate2(){
        //构造员工对象
        Emp emp = new Emp();
        emp.setId(19);
        emp.setUsername("Tom222333");
//        emp.setName("汤姆222");
//        emp.setGender((short)1);
//        emp.setUpdateTime(LocalDateTime.now());

        //执行更新员工操作
        empMapper.update2(emp);
    }
  • 映射

    xml 复制代码
    <!-- 动态更新员工-->
    <update id="update2">
        update emp
        <set>
            <if test="username != null">username = #{username},</if>
            <if test="name != null">name = #{name},</if>
            <if test="gender != null">gender = #{gender},</if>
            <if test="image != null">image = #{image},</if>
            <if test="job != null">job = #{job},</if>
            <if test="entrydate != null">entrydate = #{entrydate},</if>
            <if test="deptId != null">dept_id = #{deptId},</if>
            <if test="updateTime != null">update_time = #{updateTime}</if>
        </set>
        where id = #{id}
    </update>
  • 接口方法

    java 复制代码
    // 动态更新员工信息
    public void update2(Emp emp);

批量删除 foreach

mysql 复制代码
DELETE FROM emp WHERE id in(22,23)
  • 接口方法

    java 复制代码
    // 批量删除
    public void deleteByIds(List<Integer> ids);
  • 映射

    xml 复制代码
    <!--批量删除员工 (18,19,20)-->
    <!--
        collection: 遍历的集合
        item: 遍历出来的元素
        separator: 分隔符
        open: 遍历开始前拼接的SQL片段
        close: 遍历结束后拼接的SQL片段
    -->
    <delete id="deleteByIds">
        delete  from emp where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>
  • 测试方法

    java 复制代码
    //批量删除员工
    @Test
    public void testDeleteByIds(){
        List<Integer> ids = Arrays.asList(22,23);
        empMapper.deleteByIds(ids);
    }

SQL&include

xml 复制代码
<sql id="commonSelect">
    select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time
    from emp
</sql>


<include refid="commonSelect"/>

<!-- 二者配套使用 -->
  • < sql >:定义可重用的 SQL 片段。

  • < include >:通过属性refid,指定包含的sql片段。

相关推荐
幽络源小助理1 小时前
《已调试》SpringBoot景区寄存管理系统源码 - 免费JavaWeb项目下载 | 幽络源
java·开发语言·spring boot
脸大是真的好~1 小时前
尚硅谷-索引优化以及查询优化
java
豆沙沙包?1 小时前
2025年--Lc302-415. 字符串相加--java版
java·开发语言
天涯路s1 小时前
qt怎么将模块注册成插件
java·服务器·前端·qt
Unstoppable221 小时前
八股训练营第 37 天 | Java 内存区域有哪些部分?介绍一下什么是强引用、软引用、弱引用、虚引用?有哪些垃圾回收算法?有哪些垃圾回收器?
java·jvm·八股
JIngJaneIL1 小时前
基于Java民宿管理系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot
杰克尼1 小时前
蓝桥云课-13. 定时任务
java·开发语言·算法
脸大是真的好~1 小时前
尚硅谷-mysql专项训练-InnoDB数据存储结构-索引的创建与设计
java
竹林幽深1 小时前
集群环境下SSE的解决方案-没试记录一下
java·spring boot·后端