3.MybatisPlus插入和更新数据

上一篇博客带领大家快速入门体验了一下MybatisPlus,今天带大家学习一下MybatisPlus如何插入和更新数据,以及它自带的主键生成策略的简单使用!
如果还没有看过上一篇的MybatisPlus快速入门体验的,我把博客链接贴出来,大家可以学习完后再来阅读本篇博客:

3.1 插入数据测试

3.1.1 修改测试类

package com.kuang.mybatis_plus;

import com.kuang.mybatis_plus.mapper.UserMapper;
import com.kuang.mybatis_plus.pojo.User;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
//扫描mapper接口所在包
@MapperScan("com.kuang.mybatis_plus.mapper")
class MybatisPlusApplicationTests {

    //继承了BaseMapper,所有的方法都来自父类(我们也可以编写自己的扩展方法)
    //通过类型自动装配UserMapper接口
    @Autowired
    private UserMapper userMapper;

    //测试插入用户数据
    @Test
    public void testInsert() {
       //获取User对象
       User user = new User();
       //设置用户名和年龄以及邮箱等属性
       user.setName("JayChou");
       user.setAge(33);
       user.setEmail("zjl123@qq.com");
       //返回受影响的行数(自动帮我们生成Id)
       int result = userMapper.insert(user);
       //打印受影响行数
        System.out.println(result);
       //打印插入的用户信息
       System.out.println(user);
    }

}

3.1.2 测试结果

1.控制台输出

java联合主键更新插入操作_数据库

结果:我们可以看到SQL插入语句执行的具体步骤!

2. 查看插入结果

java联合主键更新插入操作_数据库_02

结果:成功插入一条新的用户数据!

3.测试分析

分析:但是我们发现id并不是自增的,而是随机生成的,类似于UUID,即全局的唯一id

3.2 主键生成策略

对应数据库中的主键(自增id,uuid,雪花算法、redis、zookeeper!)

3.2.1 数据库自增长序列或字段

1.概述

概述:最常见的方式,利用数据库,全数据库唯一

2.优缺点

优点

  • 简单,代码方便,性能可以接受
  • 数字ID天然排序,对分页或者需要排序的结果很有帮助

缺点

  • 不同数据库语法和实现不同,数据库迁移时候或者多数据库
  • 在单个数据库或读写分离或一主多从的情况下,只有一个主库可以生成;有单点故障的风险
  • 在性能达不到要求的情况下,比较难于扩展
  • 如果遇见多个系统需要合并或者涉及到数据迁移会相当痛苦
  • 分表分库的时候会有麻烦

3.2.2 使用UUID

1.概述

概述:常见的方式之一,可以利用数据库,也可以利用程序生成,一般来说全球唯

2.优缺点

优点

  • 简单,代码方便
  • 生成ID性能非常好,基本不会有性能问题
  • 全球唯一,在遇到数据迁移,系统数据合并,或者数据库变更等情况下,可以从容应对

缺点

  • 没有排序,无法保证趋势递增
  • UUID往往是使用字符串存储,查询的效率比较低
  • 存储空间比较大,如果是海量数据库,就需要考虑存储量的问题
  • 传输数据量大
  • 不可读

3.2.3 UUID的变种

1. UUID to Int64 方法

为了解决UUID不可读,可以使用UUID to Int64的方法

2. Comb算法
  • 为了解决UUID无序的问题,NHibernate在其主键生成方式提供了Comb算法 (combined guid/timestamp)
  • 保留GUID的10个字节,用另6个字节表示GUID生成的时间 (DataTime)

3.2.4 Redis生成ID

概述

  • 当使用数据库来生成ID性能不够要求的时候,我们可以尝试使用Redis来生成ID,这主要依赖于Redis是单线程的,所以也可以用生成全局唯一的ID
  • 可以使用Redis的原子操作INCR和INCRBY来实现
  • 可以使用Redis集群来获取更高的吞吐量

优点

  • 不依赖于数据库,灵活方便,且性能优于数据库
  • 数字ID天然排序,对分特或者需要排序的结果很有帮助

缺点

  • 如果系统中没有Redis,还需要引入新的组件,增加系统复杂度
  • 需要编码和配置的工作量比较大

3.2.5 雪花算法

1.概述

snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID

2. 核心思想

使用41bit作为毫秒数,10bit作为机器的ID (5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号 (意味着每个节点在每毫秒可以产生4096个ID),最后还有一个符号位,永远是0,几乎可以保证全球唯一!

3.3 不同的主键策略测试

3.3.1 分析@TableId注解源码

1.查看TableId注解源码
package com.baomidou.mybatisplus.annotation;

import java.lang.annotation.*;

/**
 * 表主键标识
 *
 * @author hubin
 * @since 2016-01-23
 */
@Documented
//在runtime保持政策下运行
@Retention(RetentionPolicy.RUNTIME)
//作用目标为字段
@Target(ElementType.FIELD)
public @interface TableId {

    /**
     * 字段值(驼峰命名方式,该值可无)
     */
    String value() default "";

    /**
     * 主键ID(Id类型默认是NONE,即没有主键)
     * {@link IdType}
     */
    IdType type() default IdType.NONE;
}
2.查看IdType枚举类源码
package com.baomidou.mybatisplus.annotation;

import lombok.Getter;

/**
 * 生成ID类型枚举类
 *
 * @author hubin
 * @since 2015-11-10
 */
@Getter
//IDtype是一个枚举类
public enum IdType {
    //1.常见的三种主键策略
    // 1.1 数据库ID自增
    AUTO(0),
    //1.2 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于INPUT)
    NONE(1),
    //1.3 用户手动输入ID(该类型可以通过自己注册自动填充插件进行填充)
    INPUT(2),

    //2.以下3种类型、只有当插入对象ID 为空,才自动填充
    /**
     * 2.1 ASSIGN_ID:分配ID (注意这里的主键类型必须为number或string)
     * 基于雪花算法(与3.3.0版本之前的使用ID_WORKER一样)
     * 默认实现类为com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(即雪花算法)
     */
    ASSIGN_ID(3),
    /**
     * 2.2 ASSIGN_UUID:分配UUID (注意此时的主键类型必须为String)
     * 默认实现类为com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}
     *(UUID.replace("-",""))表示可以将UUID中的"-"替换为""
     */
    ASSIGN_UUID(4),
    //2.3 ID_WORKER:默认的全局唯一id, 目前已过时,不推荐使用(在3.3.0版本后推荐使用ASSIGN_ID)
    @Deprecated
    ID_WORKER(3),
    //2.4 ID_WORKER_STR:字符串表示法,目前已过时,不推荐使用(3.3.0版本后推荐使用ASSIGN_ID)
    @Deprecated
    ID_WORKER_STR(3),
    //2.5 UUID:全局唯一id,目前已过时,不推荐使用(3.3.0版本后推荐使用ASSIGN_UUID)
    @Deprecated
    UUID(4);

    private final int key;

    IdType(int key) {
        this.key = key;
    }
}

3.3.2 使用AUTO主键策略

1.修改User实体类
package com.kuang.mybatis_plus.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data //导入无参构造,set和get方法,以及toString方法等
@AllArgsConstructor //导入有参构造
@NoArgsConstructor //再次导入无参构造,防止被有参构造覆盖掉
public class User {
    //对应数据库中的主键 (UUID, 自增I等)
    /**
      * 使用@TableID注解,设置IdType(即Id的类型,是一个枚举类)
      * 这里选择的是AUTO(即数据库ID自增,设置后记得将MySQL数据库中的ID也勾选为自增)
      */
    @TableId(type = IdType.AUTO)
    //注意:这里的ID为Long型
    private Long id; //用户编号
    private String name; //用户名
    private Integer age; //年龄
    private String email; //邮箱
}
2. 插入用户测试
package com.kuang.mybatis_plus;

import com.kuang.mybatis_plus.mapper.UserMapper;
import com.kuang.mybatis_plus.pojo.User;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
//扫描mapper接口所在包
@MapperScan("com.kuang.mybatis_plus.mapper")
class MybatisPlusApplicationTests {

    //继承了BaseMapper,所有的方法都来自父类
    //我们也可以编写自己的扩展方法
    //通过类型自动装配UserMapper接口
    @Autowired
    private UserMapper userMapper;

    //测试插入用户数据
    @Test
    public void testInsert() {
       //获取User对象
       User user = new User();
       //设置用户名和年龄以及邮箱等属性
       user.setName("Linjunjie");
       user.setAge(30);
       user.setEmail("ljj123@qq.com");
       //返回受影响的行数(自动帮我们生成Id)
       int result = userMapper.insert(user);
       //打印受影响行数
        System.out.println(result);
       //打印插入的用户信息
       System.out.println(user);
    }

}
3.修改主键ID自增

java联合主键更新插入操作_数据库_03

4.查看数据库自增值

java联合主键更新插入操作_java_04

通过观察user数据表,我们可以看到Auto Increment 的自增值为1405056510844735490

5.查看插入数据结果

java联合主键更新插入操作_mybatis_05

结果:执行完插入测试后,我们发现新用户"Linjunjie"的id值为“1405056510844735490”,符合预期要求

3.3.3 使用INPUT主键策略

1.修改User实体类
package com.kuang.mybatis_plus.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data //导入无参构造,set和get方法,以及toString方法等
@AllArgsConstructor //导入有参构造
@NoArgsConstructor //再次导入无参构造,防止被有参构造覆盖掉
public class User {
    /**
      * 使用@TableID注解,设置IdType(即Id的类型,是一个枚举类) 
      * 这里选择的是INPUT,即用户手动输入ID(由于是Long型,所以插入整数时要在后面加上L)
      */
    @TableId(type = IdType.INPUT)
    private Long id; //用户编号
    private String name; //用户名
    private Integer age; //年龄
    private String email; //邮箱
}
2.修改测试类
package com.kuang.mybatis_plus;

import com.kuang.mybatis_plus.mapper.UserMapper;
import com.kuang.mybatis_plus.pojo.User;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
//扫描mapper接口所在包
@MapperScan("com.kuang.mybatis_plus.mapper")
class MybatisPlusApplicationTests {

    //通过类型自动装配UserMapper接口
    @Autowired
    private UserMapper userMapper;

    //测试插入用户数据
    @Test
    public void testInsert() {
       //获取User对象
       User user = new User();
       //设置用户名和年龄以及邮箱等属性
       //由于主键策略采用INPUT方式,需要手动设置ID(ID为Long型,需要在6后面加上L后缀)
       user.setId(6L);
       user.setName("王力宏");
       user.setAge(39);
       user.setEmail("wlh123@qq.com");

        //返回受影响的行数(自动帮我们生成Id)
       int result = userMapper.insert(user);
       //打印受影响行数
        System.out.println(result);
       //打印插入的用户信息
       System.out.println(user);
    }

}
3.查看控制台输出

java联合主键更新插入操作_java联合主键更新插入操作_06

4.查看插入结果

java联合主键更新插入操作_java_07

结果:插入数据成功!

3.3.4 使用ASSIN_ID主键策略

1.修改User实体类
package com.kuang.mybatis_plus.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data //导入无参构造,set和get方法,以及toString方法等
@AllArgsConstructor //导入有参构造
@NoArgsConstructor //再次导入无参构造,防止被有参构造覆盖掉
public class User {
    /**
     * 使用@TableID注解,设置IdType(即Id的类型,是一个枚举类)
     * 这里选择的是ASSIGN_ID(3.3.0版本后的推荐使用的,基于雪花算法)
     * 3.3.0之前的版本推荐使用的是ID_WORKER(全局唯一ID,基于雪花算法)
     */
    @TableId(type = IdType.ASSIGN_ID)
    //注意:需要将LOng型的id修改为String型
    private String id; //用户编号
    private String name; //用户名
    private Integer age; //年龄
    private String email; //邮箱
}
2.修改测试类
package com.kuang.mybatis_plus;

import com.kuang.mybatis_plus.mapper.UserMapper;
import com.kuang.mybatis_plus.pojo.User;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
//扫描mapper接口所在包
@MapperScan("com.kuang.mybatis_plus.mapper")
class MybatisPlusApplicationTests {

    //通过类型自动装配UserMapper接口
    @Autowired
    private UserMapper userMapper;

    //测试插入用户数据
    @Test
    public void testInsert() {
       //获取User对象
       User user = new User();
       //使用ASSign_ID主键策略
       //设置用户名和年龄以及邮箱等属性
       user.setName("陈奕迅");
       user.setAge(42);
       user.setEmail("cyx123@qq.com");

        //返回受影响的行数(自动帮我们生成Id)
       int result = userMapper.insert(user);
       //打印受影响行数
        System.out.println(result);
       //打印插入的用户信息
       System.out.println(user);
    }

}
3.修改user表的id类型

java联合主键更新插入操作_数据库_08

4.查看控制台输出

java联合主键更新插入操作_java联合主键更新插入操作_09

5.查看插入结果

java联合主键更新插入操作_java_10

结果:插入数据成功!

3.3.5 使用ASSIGN_UUID主键策略

1.修改User实体类
package com.kuang.mybatis_plus.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data //导入无参构造,set和get方法,以及toString方法等
@AllArgsConstructor //导入有参构造
@NoArgsConstructor //再次导入无参构造,防止被有参构造覆盖掉
public class User {

    /**
     * 使用@TableID注解,设置IdType(即Id的类型,是一个枚举类)
     * 这里选择的是ASSIGN_UUID(相当于UUID)
     */        
    @TableId(type = IdType.ASSIGN_UUID)
    private String id; //用户编号
    private String name; //用户名
    private Integer age; //年龄
    private String email; //邮箱
}
2.修改测试类
package com.kuang.mybatis_plus;

import com.kuang.mybatis_plus.mapper.UserMapper;
import com.kuang.mybatis_plus.pojo.User;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
//扫描mapper接口所在包
@MapperScan("com.kuang.mybatis_plus.mapper")
class MybatisPlusApplicationTests {

    //通过类型自动装配UserMapper接口
    @Autowired
    private UserMapper userMapper;

    //测试插入用户数据
    @Test
    public void testInsert() {
       //获取User对象
       User user = new User();
       //使用ASSign_ID主键策略
       //设置用户名和年龄以及邮箱等属性
       user.setName("陈奕迅");
       user.setAge(42);
       user.setEmail("cyx123@qq.com");

        //返回受影响的行数(自动帮我们生成Id)
       int result = userMapper.insert(user);
       //打印受影响行数
        System.out.println(result);
       //打印插入的用户信息
       System.out.println(user);
    }

}
4.查看控制台输出

java联合主键更新插入操作_数据库_11

5.查看插入结果

java联合主键更新插入操作_数据库_12

结果:插入数据成功!

3.4 更新数据测试

3.4.1 只修改一个属性

1.修改测试类
package com.kuang.mybatis_plus;

import com.kuang.mybatis_plus.mapper.UserMapper;
import com.kuang.mybatis_plus.pojo.User;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
//扫描mapper接口所在包
@MapperScan("com.kuang.mybatis_plus.mapper")
class MybatisPlusApplicationTests {
    
    //通过类型自动装配UserMapper接口
    @Autowired
    private UserMapper userMapper;

    //测试更新
    @Test
    public void testUpdate() {
        //获取User对象
        User user = new User();
        //设置修改用户的Id
        user.setId("1405056510844735489");
        //设置用户要修改的信息
        user.setName("周杰伦");
        //通过Id修改用户,并且返回影响行数
        //注意:虽然updateById是通过Id修改信息,但是参数其实是一个对象!
        int result = userMapper.updateById(user);
        //打印受影响行数
        System.out.println(result);
    }

}
2. 控制台输出结果

java联合主键更新插入操作_java_13

3. 查看修改数据结果

java联合主键更新插入操作_mybatis_14

结果:修改数据成功!

3.4.2 修改多个属性

1.修改测试类
package com.kuang.mybatis_plus;

import com.kuang.mybatis_plus.mapper.UserMapper;
import com.kuang.mybatis_plus.pojo.User;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
//扫描mapper接口所在包
@MapperScan("com.kuang.mybatis_plus.mapper")
class MybatisPlusApplicationTests {
    
    //通过类型自动装配UserMapper接口
    @Autowired
    private UserMapper userMapper;

    //测试更新
    @Test
    public void testUpdate() {
        //获取User对象
        User user = new User();
        //设置修改用户的Id
        user.setId("1405056510844735489");
        //设置用户要修改的信息
        user.setName("周杰伦");
        user.setAge(24);
        //通过Id修改用户,并且返回影响行数
        //注意:虽然updateById是通过Id修改信息,但是参数其实是一个对象!
        int result = userMapper.updateById(user);
        //打印受影响行数
        System.out.println(result);
    }

}
2. 控制台输出结果

java联合主键更新插入操作_mybatis_15

结果:通过观察SQL预编译过程,可以发现Mybatis-Plus能够自动根据条件进行动态SQL拼接!

所有的SQL都是自动帮你动态配置的!

3. 查看修改数据结果

java联合主键更新插入操作_java_16

结果:修改数据成功!