02-MyBatis

MyBatis-Plus实现数据库crud操作

1.mp是什么

MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

2.创建并初始化数据库

快速开始 | MyBatis-Plus (baomidou.com)

  1. 创建数据库,创建数据库表

  2. 创建工程 springboot

    可以使用 Spring Initializer (opens new window)快速初始化一个 Spring Boot 工程

  3. 引入依赖

            <!-- mybatis-plus -->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.5.2</version>
            </dependency>
    
            <!--mysql-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.30</version>
            </dependency>
    
            <!--lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
    
  4. 配置数据库信息

    spring:
      datasource:
        username: root
        password: 123456
        url: "jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8"
        driver-class-name: com.mysql.cj.jdbc.Driver
    
  5. 编写实体类

    User

    package com.mj.demomptest.entity;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }
    
  6. mapper接口

    UserMapper

    package com.mj.demomptest.mapper;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.mj.demomptest.entity.User;
    
    public interface UserMapper extends BaseMapper<User> {
    
    }
    
  7. 包扫描

    package com.mj.demomptest;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    @MapperScan("com.mj.demomptest.mapper")
    /*
     mapper 是一个interface接口动态生成实现类对象
     动态生成对象默认找不到
     @MapperScan 才能找到动态生成的对象
     */
    public class DemomptestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemomptestApplication.class, args);
        }
    
    }
    
  8. 测试

    package com.mj.demomptest;
    
    import com.mj.demomptest.entity.User;
    import com.mj.demomptest.mapper.UserMapper;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    import java.util.List;
    
    @SpringBootTest
    class DemomptestApplicationTests {
    
        @Autowired
        private UserMapper userMapper;
    
    
        @Test
        public void findAll() {
            System.out.println(userMapper.selectList(null));
    
        }
    
    }
    
  9. 查看sql输出日志

    #mybatis日志
    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    

    控制台输出
    image

3.mp实现添加 修改

添加

    @Test
    public void testAdd(){
        User user = new User();
        user.setName("Lucy");
        user.setAge(20);
        user.setEmail("09876@qq.com");
        //返回影响行数
        int insert = userMapper.insert(user);
        System.out.println(insert);


    }

image

修改

    //修改
    @Test
    public void testUpdate(){

        User user = new User();
        user.setId(1585808430935887874L);
        user.setName("Mary");
        int count = userMapper.updateById(user);
        System.out.println(count);
    }

4.组件策略

1、插入操作

//添加
@Test
public void testAdd() {
    User user = new User();
    user.setName("lucy");
    user.setAge(20);
    user.setEmail("1243@qq.com");
    int insert = userMapper.insert(user);
    System.out.println(insert);
}

注意:数据库插入id值默认为:全局唯一id

1585808430935887874

2、MP的主键策略

2.1 ASSIGN_ID

MyBatis-Plus默认的主键策略是:ASSIGN_ID (使用了雪花算法)

@TableId(type = IdType.ASSIGN_ID)``private String id;

雪花算法:分布式ID生成器

雪花算法是由Twitter公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的主键的有序性。

核心思想:

长度共64bit(一个long型)。

首先是一个符号位,1bit标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0。

41bit时间截(毫秒级),存储的是时间截的差值(当前时间截 – 开始时间截),结果约等于69.73年。

10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID,可以部署在1024个节点)。

12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID)。

image

优点:整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率较高。

2.2 AUTO 自增策略

需要在创建数据表的时候设置主键自增

实体字段中配置 @TableId(type = IdType.AUTO)

@TableId(type = IdType.AUTO)
private Long id;

要想影响所有实体的配置,可以设置全局主键配置

#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto

5.mp自动填充 乐观锁

使用相同的方式填充

自动填充

  1. 准备工作

    • 在表中添加两个字段

      添加datatime类型的新的字段,create_time,update_time

    • 在表对应实体类添加对应的属性

  2. 实体类修改

    自动填充属性添加注解

        @TableField(fill = FieldFill.INSERT)
    	//添加的时候设置值
        private Date createTime;
        
        @TableField(fill = FieldFill.INSERT_UPDATE)
    	//添加的时候设置值,修改的时候不设置值
        private Date updateTime;
    
  3. 创建实体类实现接口,实现接口两个方法

    一个方法添加执行,一个方法修改执行

    设置添加什么值

    注意:不要忘记添加 @Component 注解

    package com.mj.demomptest.handler;
    
    import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
    import org.apache.ibatis.reflection.MetaObject;
    import org.springframework.stereotype.Component;
    
    import java.util.Date;
    
    @Component
    public class MyMetaObjectHandler implements MetaObjectHandler {
        
        //mp执行添加操作时
        @Override
        public void insertFill(MetaObject metaObject) {
            //属性名称,设置的值(当前时间),metaObject对象  ;当前时间 set createTime中去
            this.setFieldValByName("createTime",new Date(),metaObject);
            this.setFieldValByName("updateTime",new Date(),metaObject);
            
        }
        
        //mp执行修改时
        @Override
        public void updateFill(MetaObject metaObject) {
            this.setFieldValByName("updateTime",new Date(),metaObject);
    
        }
    }
    

乐观锁

多线程操作中或并发操作中,多人更改同一条数据,最后提交的事务,把之前的事务覆盖,丢失更新问题

  1. 取出记录时,获取当前的版本号 version
  2. 更新时,带上当前version
  3. 执行更新时, set version = newVersion where version = oldVersion 比较当前修改数据版本和数据库版本是否一样
  4. 如果 version 不对 ,就更新失败
实现
  1. 修改实体类

    在表添加字段作为版本号,在表对应实体类添加版本号属性

        @Version
        private Integer version;
    
  2. 创建配置文件 注册乐观锁插件

    创建包config,创建文件MybatisPlusConfig.java

    此时可以删除主类中的 @MapperScan 扫描注解

    package com.mj.demomptest.config;
    
    import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    @Configuration
    @MapperScan("com.mj.demomptest.mapper")
    public class MpConfig {
    
        //乐观锁插件
        @Bean
        public OptimisticLockerInterceptor optimisticLockerInterceptor() {
            return new OptimisticLockerInterceptor();
        }
    
    
    }
    

6.查询

1,查询

  1. 通过多个id批量查询

        //多个id批量查询
        @Test
        public void testSelect1(){
    
            List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
            System.out.println(users);
        }
    
  2. 简单的条件查询

        @Test
        public void testSelect2(){
    
            Map<String,Object> columnMap = new HashMap<>();
            columnMap.put("name","Jone");
            columnMap.put("age",20);
            List<User> users = userMapper.selectByMap(columnMap);
            System.out.println(users);
        }
    

2,分页

  1. 配置分页查询插件

        //分页查询插件
        @Bean
        public PaginationInterceptor paginationInterceptor() {
            return new PaginationInterceptor();
        }
    
  2. 编写分页代码

    • 插件Page对象,传入两个参数

      当前页

      每页显示数

    • 调用mp的方法实现分页

          //分页查询
          @Test
          public void testSelectPage(){
              Page<User> page = new Page(1,3);
              //new 的对象,条件
              Page<User> userPage = userMapper.selectPage(page, null);
              //返回对象得到分页所有数据
              long pages = userPage.getPages();//总页数
              long current = userPage.getCurrent();//当前页
              List<User> records = userPage.getRecords();//查询数据集合
              long total = userPage.getTotal();//总记录数
              boolean hasNext = userPage.hasNext();//现在当前页是否有下一页
              boolean hasPrevious = userPage.hasPrevious();//现在当前页是否有上一页
      
          }
      

7.删除与逻辑删除

1,删除

  1. 根据Id删除

        //id删除
        @Test
        public void testDeleteId(){
            int rows = userMapper.deleteById(1);
            System.out.println(rows);
        }
    
  2. 批量删除

    @Test
    public void testDeleteBatchIds() {
        int result = userMapper.deleteBatchIds(Arrays.asList(8, 9, 10));
        system.out.println(result);
    }
    
    
  3. 简单条件删除

    @Test
    public void testDeleteByMap() {
    	HashMap<String, Object> map = new HashMap<>();
    	map.put("name", "Helen");
    	map.put("age", 18);
    	int result = userMapper.deleteByMap(map);
    	system.out.println(result);
    }
    
    

2,逻辑删除

  1. 物理删除和逻辑删除

    物理删除:表中数据不存在了

    逻辑删除:表中数据还存在,但在查询时,查不出来

    ​ 在表添加字段,作为逻辑删除标志,每次删除时,修改标志位

  2. 逻辑删除实现流程

    • 数据库修改

      添加delete字段 作为逻辑删除的标志

    • 实体类修改

      添加deleted 字段,并加上 @TableLogic 注解

          @TableLogic
          @TableField(fill = FieldFill.INSERT)
          private Integer deleted; //逻辑删除标志
      

      MyMetaObjectHandler.java

      this.setFieldValByName("deleted",0,metaObject);
      
    • 配置(可选)

      0 – – -不删除

      1 – – – 删除

    • 测试

      注意:被删除前,数据的deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作

          @Test
          public void testLogicDelete() {
              int result = userMapper.deleteById(1585882038232223746L);
              System.out.println(result);
          }
      

      数据库中的数据并没有被删除,只是修改了 deleted的值 为1

      image

    • 测试逻辑后的删除查询

      image

8.条件构造器和常用接口

1,wapper介绍

image-20221028152744844

Wrapper : 条件构造抽象类,最顶端父类

AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件

QueryWrapper : 查询条件封装

UpdateWrapper : Update 条件封装

AbstractLambdaWrapper : 使用Lambda 语法

LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper

LambdaUpdateWrapper : Lambda 更新封装Wrapper

2,测试用例

  1. ge 、gt、le、lt、isNull、isNotNull

    @Test
    public void testSel(){
        //ge,gt,le,lt
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //表中的字段名字,值   age 大于等于21的
        queryWrapper.ge("age",21);//大于等于
        List<User> users = userMapper.selectList(queryWrapper);
        System.out.println(users);
    }
    

    sdf

  2. eq(等于)、ne(不等于)

    注意:seletOne()返回的是一条实体记录,当出现多条时会报错

        //eq ne
        @Test
        public void testSelectOne(){
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("name","Tom");
            List<User> users = userMapper.selectList(queryWrapper);
            System.out.println(users);
        }
    

    eq

  3. between、notBetween

    包含大小边界

    //between,notbetween
    @Test
    public void testSelectA(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //字段,开始值,结束值   age [22,28]
        queryWrapper.between("age",22,28);
        List<User> users = userMapper.selectList(queryWrapper);
        System.out.println(users);
    }
    

  4. like、notlike、likeLeft、likeRight(%的右边)

    update user set name like "%张"
    

    selectMap()返回Map集合列表,通常配合select()使用

        @Test
        public void testSelectB(){
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            //
            queryWrapper.like("name","J");
            List<User> users = userMapper.selectList(queryWrapper);
            System.out.println(users);
        }
    

    like

  5. orderBy、orderByDesc、orderByAsc 排序

        @Test
        public void testSelectC(){
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            //
            queryWrapper.orderByDesc("id");
            List<User> users = userMapper.selectList(queryWrapper);
            System.out.println(users);
        }
    

3,查询方式

查询方式 说明
setSqlSelect 设置 SELECT 查询字段
where WHERE 语句,拼接 + WHERE 条件
and AND 语句,拼接 + AND 字段=值
andNew AND 语句,拼接 + AND (字段=值)
or OR 语句,拼接 + OR 字段=值
orNew OR 语句,拼接 + OR (字段=值)
eq 等于=
allEq 基于 map 内容等于=
ne 不等于<>
gt 大于>
ge 大于等于>=
lt 小于<
le 小于等于<=
like 模糊查询 LIKE
notLike 模糊查询 NOT LIKE
in IN 查询
notIn NOT IN 查询
isNull NULL 值查询
isNotNull IS NOT NULL
groupBy 分组 GROUP BY
having HAVING 关键词
orderBy 排序 ORDER BY
orderAsc ASC 排序 ORDER BY
orderDesc DESC 排序 ORDER BY
exists EXISTS 条件语句
notExists NOT EXISTS 条件语句
between BETWEEN 条件语句
notBetween NOT BETWEEN 条件语句
addFilter 自由拼接 SQL
last 拼接在最后,例如:last(“LIMIT 1”)
hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 02-MyBatis