首页 > 其他分享 >动力节点2023版MyBatisPlus教程【进阶篇】

动力节点2023版MyBatisPlus教程【进阶篇】

时间:2023-04-19 10:32:59浏览次数:34  
标签:MyBatisPlus ._ private id 进阶篇 User 2023 主键 user

来自B站动力节点最新版的MybatisPlus教程,整理了笔记——第四章高级篇

4 【高级篇】

4.1 主键策略

4.1.1 主键生成策略介绍

首先大家先要知道什么是主键,主键的作用就是唯一标识,我们可以通过这个唯一标识来定位到这条数据。 当然对于表数据中的主键,我们可以自己设计生成规则,生成主键。但是在更多的场景中,没有特殊要求的话,我们每次自己手动生成的比较麻烦,我们可以借助框架提供好的主键生成策略,来生成主键。这样比较方便快捷 在MybatisPlus中提供了一个注解,是@TableId,该注解提供了各种的主键生成策略,我们可以通过使用该注解来对于新增的数据指定主键生成策略。那么在以后新增数据的时候,数据就会按照我们指定的主键生成策略来生成对应的主键。

4.1.2 AUTO策略

该策略为跟随数据库表的主键递增策略,前提是数据库表的主键要设置为自增

动力节点2023版MyBatisPlus教程【高级篇】_mybatis

此处要设置好下次递增的数字

动力节点2023版MyBatisPlus教程【高级篇】_spring_02

实体类添加注解,指定主键生成策略

@Data
@AllArgsConstructor
@NoArgsConstructorpublic class User {**    **@TableId(type = IdType._AUTO_)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
@Testvoid primaryKey(){
    User user = new User();
    user.setName("Mary");
    user.setAge(35);
    user.setEmail("[email protected]");
    userMapper.insert(user);
}

拼接的SQL语句如下

动力节点2023版MyBatisPlus教程【高级篇】_mybatisplus教程_03

4.1.3 INPUT策略

该策略表示,必须由我们手动的插入id,否则无法添加数据

@Data
@AllArgsConstructor
@NoArgsConstructorpublic class User {**    **@TableId(type = IdType._INPUT_)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

由于我们不使用AUTO了,所以把自动递增去掉

动力节点2023版MyBatisPlus教程【高级篇】_spring_04

这里如果我们省略不写id,会发现,无法插入数据

@Testvoid primaryKey(){
    User user = new User();
    user.setName("Jerry");
    user.setAge(38);
    user.setEmail("[email protected]");
    userMapper.insert(user);
}

动力节点2023版MyBatisPlus教程【高级篇】_mybatis_05

但是我们自己指定了id,发现可以添加成功

@Testvoid primaryKey(){
    User user = new User();
    user.setId(8L);
    user.setName("Jerry");
    user.setAge(38);
    user.setEmail("[email protected]");
    userMapper.insert(user);
}

4.1.4 ASSIGN_ID策略

我们来思考一下,像之前这种自动递增的方式,有什么问题?

如果我们将来一张表的数据量很大,我们需要进行分表。 常见的分表策略有两种: 【1】水平拆分

动力节点2023版MyBatisPlus教程【高级篇】_mybatisplus教程_06

水平拆分就是将一个大的表按照数据量进行拆分【2】垂直拆分

动力节点2023版MyBatisPlus教程【高级篇】_mybatisplus_07

垂直拆分就是将一个大的表按照字段进行拆分

其实我们对于拆分后的数据,有三点需求,就拿水平拆分来说:【1】之前的表的主键是有序的,拆分后还是有序的 【2】虽然做了表的拆分,但是每条数据还需要保证主键的唯一性 【3】主键最好不要直接暴露数据的数量,这样容易被外界知道关键信息 那就需要有一种算法,能够实现这三个需求,这个算法就是雪花算法

雪花算法是由一个64位的二进制组成的,最终就是一个Long类型的数值。主要分为四部分存储

【1】1位的符号位,固定值为0 【2】41位的时间戳 【3】10位的机器码,包含5位机器id和5位服务id 【4】12位的序列号

动力节点2023版MyBatisPlus教程【高级篇】_ssm框架_08

使用雪花算法可以实现有序、唯一、且不直接暴露排序的数字。

@Data
@AllArgsConstructor
@NoArgsConstructorpublic class User {
    @TableId(type = IdType._ASSIGN_ID_)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
@Testvoid primaryKey(){
    User user = new User();
    user.setName("Jerry");
    user.setAge(38);
    user.setEmail("[email protected]");
    userMapper.insert(user);
}

我们可以在插入后发现一个19位长度的id,该id就是雪花算法生成的id,这是二级制的十进制表示形式

动力节点2023版MyBatisPlus教程【高级篇】_mybatisplus教程_09

4.1.5 NONE策略

@Data
@AllArgsConstructor
@NoArgsConstructorpublic class User {
    @TableId(type = IdType._NONE_)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

NONE策略表示不指定主键生成策略,当我们没有指定主键生成策略或者主键策略为NONE的时候,他跟随的是全局策略,那我们来看一下他的全局策略默认是什么全局配置中 id-type是用于配置主键生成策略的,我们可以看一下id-type的默认值

动力节点2023版MyBatisPlus教程【高级篇】_ssm框架_10

动力节点2023版MyBatisPlus教程【高级篇】_ssm框架_11

通过查看源码发现,id-type的默认值就是雪花算法

4.1.6 ASSIGN_UUID策略

UUID(Universally Unique Identifier)全局唯一标识符,定义为一个字符串主键,采用32位数字组成,编码采用16进制,定义了在时间和空间都完全唯一的系统信息。UUID的编码规则:【1】1~8位采用系统时间,在系统时间上精确到毫秒级保证时间上的唯一性;

【2】9~16位采用底层的IP地址,在服务器集群中的唯一性; 【3】17~24位采用当前对象的HashCode值,在一个内部对象上的唯一性; 【4】25~32位采用调用方法的一个随机数,在一个对象内的毫秒级的唯一性。 通过以上4种策略可以保证唯一性。在系统中需要用到随机数的地方都可以考虑采用UUID算法。 我们想要演示UUID的效果,需要改变一下表的字段类型和实体类的属性类型 将数据库表的字段类型改为varchar(50)

动力节点2023版MyBatisPlus教程【高级篇】_mybatisplus_12

将实体类的属性类型改为String,并指定主键生成策略为IdType.ASSIGN_UUID

@Data
@AllArgsConstructor
@NoArgsConstructorpublic class User {
    @TableId(type = IdType._ASSIGN_UUID_)
    private String id;
    private String name;
    private Integer age;
    private String email;
}

完成数据的添加

@Testvoid primaryKey(){
    User user = new User();
    user.setName("Jerry");
    user.setAge(38);
    user.setEmail("[email protected]");
    userMapper.insert(user);
}

我们会发现,成功添加了一条数据,id为uuid类型

动力节点2023版MyBatisPlus教程【高级篇】_spring_13

4.1.7 小结

本章节讲解了主键生成策略,我们可以通过指定主键生成策略来生成不同的主键id,从而达到对于数据进行唯一标识的作用。

4.2 分页

分页操作在实际开发中非常的常见,我们在各种平台和网站中都可以看到分页的效果。例如:京东商城的分页效果

动力节点2023版MyBatisPlus教程【高级篇】_ssm框架_14

例如:百度的分页效果

动力节点2023版MyBatisPlus教程【高级篇】_spring_15

在MybatisPlus中我们如何配置分页呢?这里我们思考一下 在MybatisPlus中的查询语句是怎么实现的,我们可以通过两种方式实现查询语句 【1】通过MybatisPlus提供的方法来实现条件查询 【2】通过自定义SQL语句的方式来实现查询 接下来我们就来演示这两种分页方式如何实现

4.2.1 分页插件

在大部分场景下,如果我们的SQL没有这么复杂,是可以直接通过MybatisPlus提供的方法来实现查询的,在这种情况下,我们可以通过配置分页插件来实现分页效果分页的本质就是需要设置一个拦截器,通过拦截器拦截了SQL,通过在SQL语句的结尾添加limit关键字,来实现分页的效果

动力节点2023版MyBatisPlus教程【高级篇】_ssm框架_16

接下来看一下配置的步骤【1】通过配置类来指定一个具体数据库的分页插件,因为不同的数据库的方言不同,具体生成的分页语句也会不同,这里我们指定数据库为Mysql数据库

@Configurationpublic class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType._MYSQL_));
        return interceptor;
    }
}

【2】实现分页查询效果

@Testvoid selectPage(){
    **//1.创建QueryWrapper对象
    **LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    **//2.创建分页查询对象,指定当前页和每页显示条数
    **IPage<User> page = new Page<>(1,3);
    **//3.执行分页查询
    **userMapper.selectPage(page, lambdaQueryWrapper);
    **//4.查看分页查询的结果
    **System._out_.println("当前页码值:"+page.getCurrent());
    System._out_.println("每页显示数:"+page.getSize());
    System._out_.println("总页数:"+page.getPages());
    System._out_.println("总条数:"+page.getTotal());
    System._out_.println("当前页数据:"+page.getRecords());
}

动力节点2023版MyBatisPlus教程【高级篇】_mybatisplus_17

4.2.2 自定义分页插件

在某些场景下,我们需要自定义SQL语句来进行查询。接下来我们来演示一下自定义SQL的分页操作【1】在UserMapper.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.powernode.mapper.UserMapper">

     <select id="selectByName" resultType="com.powernode.domain.User">
        select * from powershop_user where name = #{name}
     </select>

</mapper>

【2】在Mapper接口中提供对应的方法,方法中将IPage对象作为参数传入

@Mapperpublic interface UserMapper extends BaseMapper<User> {
       IPage<User> selectByName(IPage<User> page, String name);
}

【3】表数据为

动力节点2023版MyBatisPlus教程【高级篇】_spring_18

【4】实现分页查询效果

@Testvoid selectPage2(){
    **//1.创建分页查询对象,指定当前页和每页显示条数
    **IPage<User> page = new Page<>(1,2);
    **//2.执行分页查询
    **userMapper.selectByName(page,"Mary");
    **//3.查看分页查询的结果
    **System._out_.println("当前页码值:"+page.getCurrent());
    System._out_.println("每页显示数:"+page.getSize());
    System._out_.println("总页数:"+page.getPages());
    System._out_.println("总条数:"+page.getTotal());
    System._out_.println("当前页数据:"+page.getRecords());
}

4.2.3 小结

这里我们学习了两种分页的配置方法,将来以后我们在进行条件查询的时候,可以使用分页的配置进行配置。

4.3 ActiveRecord模式

4.3.1 ActiveRecord介绍

ActiveRecord(活动记录,简称AR),是一种领域模型模式,特点是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一行记录。ActiveRecord 一直广受解释型动态语言( PHP 、 Ruby 等)的喜爱,通过围绕一个数据对象进行CRUD操作。而 Java 作为准静态(编译型)语言,对于 ActiveRecord 往往只能感叹其优雅,所以 MP 也在 AR 道路上进行了一定的探索,仅仅需要让实体类继承 Model 类且实现主键指定方法,即可开启 AR 之旅。

4.3.2 ActiveRecord实现

接下来我们来看一下ActiveRecord的实现步骤【1】让实体类继承Model类

@Data
@AllArgsConstructor
@NoArgsConstructorpublic class User extends Model<User> {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

我们可以看到,Model类中提供了一些增删改查方法,这样的话我们就可以直接使用实体类对象调用这些增删改查方法了,简化了操作的语法,但是他的底层依然是需要UserMapper的,所以持久层接口并不能省略【2】测试ActiveRecord模式的增删改查添加数据

@Testvoid activeRecordAdd(){
    User user = new User();
    user.setName("wang");
    user.setAge(35);
    user.setEmail("[email protected]");
    user.insert();
}

删除数据

@Testvoid activeRecordDelete(){
    User user = new User();
    user.setId(8L);
    user.deleteById();
}

修改数据

@Testvoid activeRecordUpdate(){
    User user = new User();
    user.setId(6L);
    user.setAge(50);
    user.updateById();
}|

查询数据

@Testvoid activeRecordSelect(){
    User user = new User();
    user.setId(6L);
    User result = user.selectById();
    System._out_.println(result);
}

4.4 SimpleQuery工具类

4.4.1 SimpleQuery介绍

SimpleQuery可以对selectList查询后的结果用Stream流进行了一些封装,使其可以返回一些指定结果,简洁了api的调用

4.4.2 list

演示基于字段封装集合

@Testvoid testList(){
    List<Long> ids = SimpleQuery._list_(new LambdaQueryWrapper<User>().eq(User::getName, "Mary"), User::getId);
    System._out_.println(ids);
}

演示对于封装后的字段进行lambda操作

@Testvoid testList2(){
    List<String> names = SimpleQuery._list_(new LambdaQueryWrapper<User>().eq(User::getName, "Mary"),User::getName,e ->  Optional._of_(e.getName()).map(String::toLowerCase).ifPresent(e::setName));
    System._out_.println(names);
}

4.4.3 map

演示将所有的对象以id,实体的方式封装为Map集合

@Testvoid testMap(){
    **//将所有元素封装为Map形式
    **Map<Long, User> idEntityMap = SimpleQuery._keyMap_(
            new LambdaQueryWrapper<>(), User::getId);
    System._out_.println(idEntityMap);
}

演示将单个对象以id,实体的方式封装为Map集合

@Testvoid testMap2(){
    **//将单个元素封装为Map形式
    **Map<Long, User> idEntityMap = SimpleQuery._keyMap_(
            new LambdaQueryWrapper<User>().eq(User::getId,1L), User::getId);
    System._out_.println(idEntityMap);
}

演示只想要id和name组成的map

@Testvoid testMap3(){
    **//只想要只想要id和name组成的map
    **Map<Long, String> idNameMap = SimpleQuery._map_(new LambdaQueryWrapper<>(), User::getId, User::getName);
    System._out_.println(idNameMap);
}

4.4.4 Group

演示分组效果

@Testvoid testGroup(){
    Map<String, List<User>> nameUsersMap = SimpleQuery._group_(new LambdaQueryWrapper<>(), User::getName);
    System._out_.println(nameUsersMap);
}

4.4.5 小结

在这一小节,我们演示了SimpleQuery提供的Stream流式操作的方法,通过这些操作继续为我们提供了查询方面简化的功能

标签:MyBatisPlus,._,private,id,进阶篇,User,2023,主键,user
From: https://blog.51cto.com/u_15083739/6205791

相关文章

  • .NET周报 【4月第3期 2023-04-15】
    国内文章SemanticKernel入门系列:......
  • 产品原型15-20230418
               ......
  • 2023.4.18
    1//例8.12#include<iostream>3usingnamespacestd;4classComplex5{6public:7Complex(doubler=0.0,doublei=0.0):real(r),image(i){}8Complexoperator+(constComplex&c2)const;9Complexoperator-(constComplex......
  • day49(2023.4.18)
    1.MySQL事务 2.使用事务 3.事务的并发问题 4.事务的隔离级别 5.用户管理 6.使用Navicat创建用户  7.使用Navicat分配权限8.测试一下分配好的权限 9.删除用户 10.数据的导出 11.分页查询  day49(2023.4.18)......
  • 2023/4/18每日随笔
       今天,上了英语口语,数据库,和python,数据库课上学了需求分析,数据库的建立等等,是一些以后做项目的要用到的东西。然后,python课上写报告,然后跑了八圈,晚上写了项目,解决了Androidfragment的添加bug,以及数据传输问题,我写的很乱,我觉得应该有一个东西可以在整个项目共享,但是我不知道......
  • 2023/4/18
    7-1用虚函数分别计算各种图形的面积分数 20全屏浏览题目切换布局作者 沙金单位 石家庄铁道大学定义抽象基类Shape,由它派生出五个派生类:Circle(圆形)、Square(正方形)、Rectangle(长方形)、Trapezoid(梯形)和Triangle(三角形),用虚函数分别计算各种图形的......
  • 变编程一小时2023.4.18
    1.#include<iostream>usingnamespacestd;classShape{ public: virtualdoublearea()const=0;};classCircle:publicShape{ public: Circle(doubler):radius(r) { } virtualdoublearea()const { return3.14159*radius*radius; } protected: dou......
  • java学习日记20230414-HashSet源码
    HashSetHashSet底层是HashMap添加一个元素时,先得到Hash值,会转化成索引值;找到存储数据表table,看这个索引位置是否存放元素;如果没有直接加入如果有,调用equals比较,如果相同放弃添加,如果不同,则添加到最后在java8中,如果一条链表的元素个数到达TREEIFY_THRESHOLD(默认是8)(table表......
  • It's all but a dream(JSOI2023 追忆)
    联赛220,队线265,哈哈。day0下午先去了华山,进行了一个喝茶???看着联赛270+的队爷们,感觉人类的悲欢并不相通。晚上试机,由于并不会用Vim,计划sublime写+code::blocks调。先配了code::blocks,然后发现并不能运行???查了下发现是xterm没装,尝试自己装一下,然后发现密码并不是123......
  • 2023/3/4[LC:Random_List_Copy]
    2023/3/4[LC:Random_List_Copy]1>心得:写“for"循环之前需要首先思考循环目的和结束条件;例如链表的遍历等;模拟仔细;2>思路首先如果是单纯复制一个普通链表:需要给前一个copy结点留一个pre指针;以便:pre->next=copy;3>解法此题有两个解法问题的关键在于如何解决指向与当前结......