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片段。

相关推荐
管鲍考试学习系统22 分钟前
在线考试系统是什么?功能、部署、应用场景全详解(管鲍考试学习系统 V8.0 深度版)
学习·架构·在线考试·考试系统·培训考试·考试练习
han_hanker26 分钟前
@Validated @Valid 用法
java·spring boot
小CC吃豆子28 分钟前
详细介绍一下静态分析工具 SonarQube
java
CheerWWW29 分钟前
深入理解计算机系统——位运算、树状数组
笔记·学习·算法·计算机系统
DevOpenClub31 分钟前
全国三甲医院主体信息 API 接口
java·大数据·数据库
言慢行善38 分钟前
SpringBoot中的注解介绍
java·spring boot·后端
一勺菠萝丶41 分钟前
管理后台使用手册在线预览与首次登录引导弹窗实现
java·前端·数据库
无巧不成书02181 小时前
Java包(package)全解:从定义、使用到避坑,新手零基础入门到实战
java·开发语言·package·java包
身如柳絮随风扬1 小时前
SpringMVC 异常处理?Spring 父子容器?
java·spring·mvc
鬼先生_sir1 小时前
Spring AI Alibaba 用户使用手册
java·人工智能·springai