简介

1. MyBatisPlus 介绍

MyBatis-Plus( 简称 MP),是一个 MyBatis 的增强工具包,只做增强不做改变**.** 为简化开

发工作、提高生产率而生

我们的愿景是成为 Mybatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。

2. 代码及文档发布地址

官方地址:

http://mp.baomidou.com

代码发布地址:

Github: https://github.com/baomidou/mybatis-plus

Gitee: https://gitee.com/baomidou/mybatis-plus

文档发布地址:

http://mp.baomidou.com/#/?id=%E7%AE%80%E4%BB%8B

集成MP

1 . 创建数据库表

-- 创建库
CREATE DATABASE mp;
-- 使用库
USE mp;
-- 创建表
CREATE TABLE tbl_employee(id INT(11) PRIMARY KEY AUTO_INCREMENT,last_name VARCHAR(50),email VARCHAR(50),gender CHAR(1),age int
);
INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Tom','tom@atguigu.com',1,22);
INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Jerry','jerry@atguigu.com',0,25);
INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Black','black@atguigu.com',1,30);
INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('White','white@atguigu.com',0,35);

2. 添加依赖

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.6.RELEASE</version><relativePath/> <!-- lookup parent from repository -->
</parent>]<properties><java.version>1.8</java.version>
</properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.20</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
</dependencies>

3. 引入数据源,配置数据源信息

通用CRUD

基于 Mybatis

  • 需要编写 EmployeeMapper 接口,并手动编写 CRUD 方法

  • 提供 EmployeeMapper.xml 映射文件,并手动编写每个方法对应的 SQL 语句.

基于 MP

  • 只需要创建 EmployeeMapper 接口, 并继承 BaseMapper 接口.这就是使用 MP

    (泛型指定的就是当前Mapper接口所操作的实体类)

  • 需要完成的所有操作,甚至不需要创建 SQL 映射文件。

生成id的策略

描述
AUTO 数据库ID自增
NONE 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUT insert前自行set主键值
ASSIGN_ID 分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)(它是Twitter开源的由64位整数组成分布式ID,性能较高,并且在单机上递增。)
ASSIGN_UUID 分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认default方法)(一串唯一随机36位字符串(32个字符串+4个“-”)的算法,十六进制)
ID_WORKER 分布式全局唯一ID 长整型类型(please use ASSIGN_ID)
UUID 32位UUID字符串(please use ASSIGN_UUID)
ID_WORKER_STR 分布式全局唯一ID 字符串类型(please use ASSIGN_ID)

雪花算法

snowflake的结构如下(每部分用-分开):

0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000

第一位为未使用,接下来的41位为毫秒级时间(41位的长度可以使用69年),然后是5位datacenterId和5位workerId(10位的长度最多支持部署1024个节点) ,最后12位是毫秒内的计数(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号)

一共加起来刚好64位,为一个Long型。(转换成字符串后长度最多19)

snowflake生成的ID整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和workerId作区分),并且效率较高。经测试snowflake每秒能够产生26万个ID。

/*** Twitter_Snowflake<br>* SnowFlake的结构如下(每部分用-分开):<br>* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br>* 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br>* 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)* 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br>* 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId<br>* 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号<br>* 加起来刚好64位,为一个Long型。<br>* SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。*/
public class SnowflakeIdWorker {// ==============================Fields===========================================/** 开始时间截 (2015-01-01) */private final long twepoch = 1420041600000L;/** 机器id所占的位数 */private final long workerIdBits = 5L;/** 数据标识id所占的位数 */private final long datacenterIdBits = 5L;/** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */private final long maxWorkerId = -1L ^ (-1L << workerIdBits);/** 支持的最大数据标识id,结果是31 */private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);/** 序列在id中占的位数 */private final long sequenceBits = 12L;/** 机器ID向左移12位 */private final long workerIdShift = sequenceBits;/** 数据标识id向左移17位(12+5) */private final long datacenterIdShift = sequenceBits + workerIdBits;/** 时间截向左移22位(5+5+12) */private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;/** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */private final long sequenceMask = -1L ^ (-1L << sequenceBits);/** 工作机器ID(0~31) */private long workerId;/** 数据中心ID(0~31) */private long datacenterId;/** 毫秒内序列(0~4095) */private long sequence = 0L;/** 上次生成ID的时间截 */private long lastTimestamp = -1L;//==============================Constructors=====================================/*** 构造函数* @param workerId 工作ID (0~31)* @param datacenterId 数据中心ID (0~31)*/public SnowflakeIdWorker(long workerId, long datacenterId) {if (workerId > maxWorkerId || workerId < 0) {throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));}if (datacenterId > maxDatacenterId || datacenterId < 0) {throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));}this.workerId = workerId;this.datacenterId = datacenterId;}// ==============================Methods==========================================/*** 获得下一个ID (该方法是线程安全的)* @return SnowflakeId*/public synchronized long nextId() {long timestamp = timeGen();//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常if (timestamp < lastTimestamp) {throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));}//如果是同一时间生成的,则进行毫秒内序列if (lastTimestamp == timestamp) {sequence = (sequence + 1) & sequenceMask;//毫秒内序列溢出if (sequence == 0) {//阻塞到下一个毫秒,获得新的时间戳timestamp = tilNextMillis(lastTimestamp);}}//时间戳改变,毫秒内序列重置else {sequence = 0L;}//上次生成ID的时间截lastTimestamp = timestamp;//移位并通过或运算拼到一起组成64位的IDreturn ((timestamp - twepoch) << timestampLeftShift) //| (datacenterId << datacenterIdShift) //| (workerId << workerIdShift) //| sequence;}/*** 阻塞到下一个毫秒,直到获得新的时间戳* @param lastTimestamp 上次生成ID的时间截* @return 当前时间戳*/protected long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp;}/*** 返回以毫秒为单位的当前时间* @return 当前时间(毫秒)*/protected long timeGen() {return System.currentTimeMillis();}//==============================Test=============================================/** 测试 */public static void main(String[] args) {SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0);for (int i = 0; i < 1000; i++) {long id = idWorker.nextId();System.out.println(Long.toBinaryString(id));System.out.println(id);}}
}

MyBatis-plus是默认开启驼峰命名转换的

@Data
@Component
@AllArgsConstructor
@NoArgsConstructor
//@TableName("employee")
public class Employee {@TableId(value = "id",type = IdType.AUTO)private Integer id;@TableField(value="last_name") //一般来说开启驼峰命名转换就可以了private String lastName;private String email;private Integer gender;private Integer age;@TableField(exist = false) //表名这个字段不在数据库表中private Integer salary;
}

生成id的策略也可以在配置文件中配置

mybatis-plus:type-aliases-package: top.codekiller.mybatispluslearn.pojomapper-locations: classpath:/mapper/*.xmlglobal-config:db-config:table-prefix: tbl_id-type: assign_id#默认开启,不配也可以configuration:map-underscore-to-camel-case: true

获取主键自增主键的值

在原生mybatis中,需要使用

<insert id="insert" useGeneratedKeys="true" keyProperty="id"></insert>

而在MP中,可以直接获取

Integer key=employee.getId();

在MP中,insert支持插入空数据

 //Employee employee=new Employee(0,"MP","123@qq.com",1,16,5000);
Employee employee=new Employee(0,"MP","123@qq.com",1);
Integer result=employeeMapper.insert(employee);#插入结果
+----+-----------+-------------------+--------+------+
| id | last_name | email             | gender | age  |
+----+-----------+-------------------+--------+------+
| 14 | MP        | 123@qq.com        | 1      | NULL |
+----+-----------+-------------------+--------+------+

更新数据

Employee employee=new Employee(6,"MP2","12345@qq.com",0,20);
Integer result=employeeMapper.updateById(employee);

查询数据(含简单分页查询)

//1. 通过id查询
Employee employee=employeeMapper.selectById(6);//2. 通过多个列进行查询 id+lastName
Map<String,Object> map=new HashMap<>();
map.put("gender",1);
map.put("email","123@qq.com");
List<Employee> list =employeeMapper.selectByMap(map);
list.forEach(((value)-> System.out.println(value)));//3. 通过多个id进行查询
List<Employee> list=employeeMapper.selectBatchIds(Arrays.asList(13,14));
list.forEach((value)-> System.out.println(value));//4. 分页查询(需要配置插件,否则getRecords是获取全部数据。配置插件后通过limit进行查询)
Page<Employee> page =employeeMapper.selectPage(new Page<Employee>(2,2),null);
List<Employee> list=page.getRecords();
list.forEach((value)-> System.out.println(value));
@Configuration
@MapperScan("top.codekiller.mybatispluslearn.mapper")
public class MybatisPlusConfig {@Beanpublic PaginationInterceptor paginationInterceptor() {PaginationInterceptor paginationInterceptor = new PaginationInterceptor();// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false// paginationInterceptor.setOverflow(false);// 设置最大单页限制数量,默认 500 条,-1 不受限制// paginationInterceptor.setLimit(500);// 开启 count 的 join 优化,只针对部分 left joinpaginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));return paginationInterceptor;}
}

删除数据

public int testCommonDelete(){//1. 通过id查询Integer result=employeeMapper.deleteById(11);//2.通过多个列删除Map<String,Object> map=new HashMap<>();map.put("id","12");map.put("last_name","MP");Integer result=employeeMapper.deleteByMap(map);//3. 通过多个id删除,我这里并不存在id为15的值,因此result=2Integer result=employeeMapper.deleteBatchIds(Arrays.asList(13,14,15));return result;
}

总结

以上是基本的 CRUD 操作,如您所见,我们仅仅需要继承一个 BaseMapper 即可实现大部分单表 CRUD 操作。BaseMapper 提供了多达 17 个方法给大家使用, 可以极其方便的实现单一、批量、分页等操作。极大的减少开发负担,难道这就是 MP 的强大之处了吗?

现有一个需求,我们需要分页查询 tbl_employee 表中,年龄在 18~50 之间性别为男且姓名为 xx 的所有用户,这时候我们该如何实现上述需求呢?

MyBatis : 需要在 SQL 映射文件中编写带条件查询的 SQL,并基于 PageHelper 插件完成分页. 实现以上一个简单的需求,往往需要我们做很多重复单调的工作。普通的 Mapper能够解决这类痛点吗?

MP: 依旧不用编写 SQL 语句, MP 提供了功能强大的条件构造器 EntityWrapper

MP启动注入SQL原理分析

问题: xxxMapper 继承了 BaseMapper, BaseMapper 中提供了通用的 CRUD 方法, 方法来源于 BaseMapper, 有方法就必须有 SQL, 因为 MyBatis 最终还是需要通过 SQL 语句操作数据.

Mybatis的源码分析

Debug

EmployeeMapper 的本质 com.baomidou.mybatisplus.core.override.MybatisMapperProxy

会创建一个MybatisMapperProxy,根据作者的注释,其实就是copy了一份MapperProxy的代码

mybatis-plus超详细介绍相关推荐

  1. MyBatis超详细介绍——SQL语句构建器类

    MyBatis超详细介绍--SQL语句构建器类 (本文作为学习笔记,了解更多请参考:MyBatis参考文档) MyBatis3提供了SQL类帮助构造SQL语句: private String sele ...

  2. 卷积神经网络超详细介绍

    文章目录 1.卷积神经网络的概念 2. 发展过程 3.如何利用CNN实现图像识别的任务 4.CNN的特征 5.CNN的求解 6.卷积神经网络注意事项 7.CNN发展综合介绍 8.LeNet-5结构分析 ...

  3. 卷积神经网络(CNN)超详细介绍

    文章转自:https://blog.csdn.net/jiaoyangwm/article/details/80011656 文章目录 1.卷积神经网络的概念 2. 发展过程 3.如何利用CNN实现图 ...

  4. 卷积神经网络超详细介绍1

    1.卷积神经网络的概念 2. 发展过程 3.如何利用CNN实现图像识别的任务 4.CNN的特征 5.CNN的求解 6.卷积神经网络注意事项 7.CNN发展综合介绍 8.LeNet-5结构分析 9.Al ...

  5. 垃圾收集概述和垃圾收集算法(超详细介绍)

    文章目录 垃圾收集概述和垃圾收集算法(超详细介绍) 为什么我们还要去了解垃圾收集和内存分配 哪些内存需要回收 不需要回收的 需要回收的 方法区的回收 回收废弃常量 回收"不再被使用的类&qu ...

  6. 怎么批量修改html文件后缀,如何批量修改文件后缀名 超详细介绍

    如何批量修改文件后缀名 超详细介绍.比如我们保持图片的时候,不是我们要的jpg格式的,需要一个一个去修改她的后缀名.现在小编就教大家快速的,批量的,安全的修好多数的文件后缀名.希望能帮大家平时的工作. ...

  7. 卷积神经网络超详细介绍(转载)

    卷积神经网络超详细介绍 文章目录 1.卷积神经网络的概念 2. 发展过程 3.如何利用CNN实现图像识别的任务 4.CNN的特征 5.CNN的求解 6.卷积神经网络注意事项 7.CNN发展综合介绍 8 ...

  8. AIOT核心技术之一--37种传感器超详细介绍

    AIOT核心技术之一–37种传感器超详细介绍 我们知道,传感器对于AIOT来说是最核心的技术之一,在物理层中几乎就是通过各种传感器来从周围读取数据用网络技术传给应用层的人工智能.机器学习.大数据等领域 ...

  9. Spring Boot整合Mybatis【超详细】

    pring Boot整合Mybatis 配置文件形式 pom.xml 配置数据源 UserMapper.xml UserMapper 配置springboot整合mybatis 在运行类上添加@Map ...

  10. 【目标检测】56、目标检测超详细介绍 | Anchor-free/Anchor-based/Backbone/Neck/Label-Assignment/NMS/数据增强

    文章目录 1.双阶段和单阶段目标检测器 1.1 双阶段目标检测器 1.1.1 R-CNN 1.1.2 SPP 1.1.3 Fast R-CNN 1.1.4 Faster R-CNN 1.2 单阶段目标 ...

最新文章

  1. centos升级mysql到5.5
  2. 面包板上的高频放大电路
  3. Java黑皮书课后题第7章:7.4(分析成绩)编写一个程序,读入个数不确定的考试分数,并且判断有多少个分数是大于或等于平均分,多少个分数是低于平均分的。输入一个负数表示输入结束。假设最高分是100
  4. 音视频技术开发周刊 | 175
  5. 作者:庄会富(1985-),男,中国科学院昆明植物研究所科技信息中心主管
  6. 基于op07的k型热电偶测量电路_基于OP07和LTC1543温度采集模块的设计
  7. iPhone8带来AR新技术,AR游戏要火了吗?
  8. Silverlight客户端和WCF服务器端共享类库
  9. Python函数声明以及与其他编程语言数据类型的比较
  10. Atitit 提升水平 把代码写的有技术含量 目录 1. 提高可读性(重要) 2 1.1. 异常模式代替返回值 2 1.2. Dsl 2 1.3. 流畅接口方法链 2 1.4. 层次结构抽象 2 1
  11. ubunt之一些问题解决办法
  12. 多载波瑞利信道matlab,瑞利信道仿真matlab.doc
  13. Android通过第三方软件打开Word、Excel、PPT、PDF等文档
  14. ssh-keygen命令使用
  15. 用线性规划解决配方问题
  16. Enable VT-x in your BIOS security settings, ensure that HAXM is installed properly
  17. MVC.Net: 解决Attempted to access an unloaded appdomain的问题
  18. 干活的累死累活,数据分析师最后还要会写PPT的5条原则
  19. Latex Misplaced alignment tab character . 的一种可能错误
  20. android的电子秤课程设计,课程设计,基于AT89C51的数字电子秤设计分享

热门文章

  1. howler.js_Howler.js可能是周围最好JavaScript音频库
  2. 玩好信用卡,它就是你东山再起的资本
  3. mqtt broker(代理/服务器)mosquitto的安装 配置 使用
  4. Java中Person类型赋值_Java设计:定义一个Person类和它的子类Employee。Person类有姓名、地址、电话号码和电子邮箱,...
  5. 【转载】人生如梦游戏间,RPG游戏开源开发讲座(JAVA篇)[3]——邯郸学步
  6. 清华2020计算机系张晨,本科三篇顶会一作、超算竞赛冠军,2020清华本科特奖结果出炉...
  7. PTA基础题目集 7-25 念数字 (15 分)
  8. 【Codecs系列】HEVC-SCC编码技术汇总
  9. 传统企业如何搭上互联网+的大船
  10. 【PowerApps 基础函数介绍】