MybatisPlus
概述
官网
https://www.baomidou.com/pages/24112f/
增删改查
前期准备参考
https://blog.csdn.net/m0_37613503/article/details/128895820?spm=1001.2014.3001.5502
只有让mapper接口继承BaseMapper,才能使用mp自带的增删改查
- 小示例
testadd,如果id写null,mp会自动生成一个long类型的数字作为id
mp的注解说明
@TableName
表名注解,标识实体类对应的表。即作类名跟表名的映射
没有该注解,程序就会认为实体类的名字就是表名,如果表名跟实体类名不一致就会报错
加上表名注解后
@TableField
如果实体类的属性名和表的字段名不一致,可以通过该注解用value来设置
-
exist
因为业务需求实体类可能会加一些属性,但表里面没有也不需要
此时可以用exist=false来让数据库忽略该属性,避免sql报错
-
select
如果不想让数据库查询某个字段,可以select=false
@TableId
主键注解,其中IdType主键类型说明
在无注解的情况下,插入数据时不给id赋值,mp会根据雪花算法生成一个随机的long类型数字
现在插入两条数据
如果想自增,首先要把表中的主键改成自增,然后还要在id属性那加@TableId的auto才行
新增的数据的id就会比表中最大的id大1
如果要改回正常的数字,就需要把所有long数据都改成正常的数字,并在表设计中修改自动增量
最大数字为9,所以改成10,自动增量就是下一个id的数字
@TableLogic
表字段逻辑处理注解(逻辑删除)
逻辑删除就是在添加一个字段来标记该数据是可用还是不可用的状态,或者未删除已删除状态
逻辑删除区别于物理删除,物理删除是把数据本身从表中删除掉,而逻辑删除并不会把数据删除,只是加个标记
在表里添加deleted字段
在实体类加上对应属性
查询所有,发现多了where deleted=0
因为在yml加个全局配置或者单独用@TableLogic使mp做了逻辑删除判断
当然如果想查询包括已删除的数据,那么可以自己写个sql语句来实现,m和mp不冲突
现在删除id=10的数据,实际是更新,把id=10数据的deleted改成1
@Version
乐观锁注解,当要更新一条记录的时候,希望这条记录没有被别人更新
悲观锁和乐观锁
有两个人同时往同一个账户存钱,如果什么方式都不采用
那后一个存完钱的人假设是B,存完钱后发现余额是130。这明显是不对的
如果采用悲观锁的方式
A存钱时,会锁住表导致B无法获取到账户余额。B需要等待A存完钱才能开始存钱
A存完了,B会看到余额变成120
悲观锁能保证数据的安全准确,但效率很低,不适合高并发的情况。在高并发状态用悲观锁会导致其余请求等待甚至超时。
而采用乐观锁会在表中新增version字段,乐观锁不会锁表,AB都能同时存钱,假设在微观上A先存完钱,更新余额的同时会更新version,从1变成2。
宏观上AB同时存完钱,但B存完钱时第一个次请求是失败的
此时version=2了,所以B的sql请求会失效,通过程序使where version+1=2
再次请求后才会成功,此时余额120+30
具体实现
先在表中加version和balance字段
执行更新的操作需要拦截器,在官网复制粘贴
实体类中添加version和balance属性
模拟AB同时存钱且不做任何处理
把@version注释掉模拟不做任何处理
通过断点调试来模拟AB同时存钱
先让A执行完程序,此时余额变成120
再让B执行完,此时余额变成130
再用乐观锁做一遍
A断点执行完程序,版本就+1了,余额也变成120
再执行完B,虽然没有报错,但并没有更新数据。因为版本号不对了
接着就是后续的业务处理了,如更新条数为0时,重新获取当前version再更新数据
分页查询
在MPconfig中加上一行代码配置分页的拦截器
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
就可以写分页了,在测试类中
先写selectPage方法,然后发现方法需要传一个page分页对象当参数
点进selectPage方法查看page对象,继承自Ipage接口,而该接口有两个实现类,这里选Page类
条件构造器
Wrapper封装了条件查询的一些方法,所以被叫做条件构造器
而抽象类Wrapper的子类中有两个是常用的
常规方法
用于复杂条件的查询
不过这种常规的方法有个缺点,字段名容易写错
下面是wrapper的一些方法具体作用
推荐方法
这种方法idea有提示,就不容易出错
复杂的sql更推荐写在xml里
代码生成器
pom
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
快速生成
user_info改成xxx_user_info
新建xxx_dept_info表,ID自增
一般写在test的java目录中
COdeGenerator.java
package com.benson;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.Collections;
public class CodeGenerator {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql:///test", "root", "123456")
.globalConfig(builder -> {
builder.author("benson") // 设置作者
//.enableSwagger() // 开启 swagger 模式
//.fileOverride() // 覆盖已生成文件
.outputDir("D:\\Programme\\code\\demo\\demomp\\src\\main\\java"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("com.benson") // 设置父包名
.moduleName("user") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.xml, "D:\\Programme\\code\\demo\\demomp\\src\\main\\resources\\mapper\\user" )); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("xxx_user_info,xxx_dept_info") // 设置需要生成的表名
.addTablePrefix("xxx_"); // 设置过滤表前缀
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
}
测试效果,记得在mapper接口加@Mapper或启动类上扫包@MapperScan("com.benson.*.mapper")
交互式生成
CodeGenerator2.java
package com.benson;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class CodeGenerator2 {
public static void main(String[] args) {
FastAutoGenerator.create(new DataSourceConfig.Builder("jdbc:mysql:///test", "root", "123456"))
// 全局配置
.globalConfig((scanner, builder) -> builder.author(scanner.apply("请输入作者名称?")).fileOverride())
// 包配置
.packageConfig((scanner, builder) -> builder.parent(scanner.apply("请输入包名?")))
// 策略配置
.strategyConfig((scanner, builder) -> builder.addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all")))
.controllerBuilder().enableRestStyle().enableHyphenStyle()
.entityBuilder().enableLombok().addTableFills(
new Column("create_time", FieldFill.INSERT)
).build())
/*
模板引擎配置,默认 Velocity 可选模板引擎 Beetl 或 Freemarker
.templateEngine(new BeetlTemplateEngine())
.templateEngine(new FreemarkerTemplateEngine())
*/
.templateEngine(new FreemarkerTemplateEngine())
.execute();
}
// 处理 all 情况
protected static List<String> getTables(String tables) {
return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
}
}