MybatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发、提供效率。
目录
一、环境准备
1.1 idea创建springboot项目
碰到了一个小问题,通过idea创建springboot时,连接超时
解决办法:使用https://start.aliyun.com 阿里云的脚手架即可
1.2 添加依赖
pom.xml
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<!--Druid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
1.3 资源配置
application.yml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC
username: root
password: 123456
1.4 实体类创建
@Data
public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
}
1.5 dao接口
@Mapper
public interface UserDao extends BaseMapper<User> {
}
到这里环境准备完毕
二、标准CRUD使用
2.1 基础增删改查的使用
@SpringBootTest
class MybatisplusStudyApplicationTests {
@Autowired
private UserDao userDao;
/**
* 查询所有
*/
@Test
void getAll() {
List<User> users = userDao.selectList(null);
System.out.println(users);
}
/**
* 根据id查询
*/
@Test
void getById(){
User user = userDao.selectById(1);
System.out.println(user);
}
/**
* 添加
*/
@Test
void add(){
User user = new User();
user.setName("pyh");
user.setAge(18);
user.setPassword("1234");
user.setTel("12138");
userDao.insert(user);
}
/**
* 根据id删除
*/
@Test
void deleteById(){
userDao.deleteById(1459813676565766146L);
}
/**
* 修改
*/
@Test
void update(){
User user = new User();
user.setId(1L);
user.setName("cat666");
userDao.updateById(user);
}
}
2.2 分页制作
添加拦截器
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mpi(){
//1 创建MybatisPlusInterceptor拦截器对象
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//2 添加分页拦截器
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
测试
/**
* 分页
*/
@Test
void getPage(){
IPage<User> page = new Page<>(2,3);
userDao.selectPage(page,null);
long pages = page.getPages();
List<User> records = page.getRecords();
long size = page.getSize();
long current = page.getCurrent();
long total = page.getTotal();
System.out.println("当前页: "+current);
System.out.println("每页显示几条数据: "+size);
System.out.println("一共有多少数据: "+total);
System.out.println("一共多少页: "+pages);
System.out.println("当前页的数据: "+records);
}
三、DQL编程控制
3.1 条件查询
3.1.1 多条件构建
查询数据库表中,年龄在10岁到30岁之间的用户信息
User::getAget,为lambda表达式中的,类名::方法名
@Test
void getAge(){
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//查询数据库表中,年龄在10岁到30岁之间的用户信息
lqw.gt(User::getAge,10).lt(User::getAge,30);
List<User> users = userDao.selectList(lqw);
System.out.println(users);
}
查询数据库表中,年龄小于10或年龄大于30的数据
@Test
void getAge1(){
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//查询数据库表中,年龄小于10或年龄大于30的数据
lqw.lt(User::getAge,10).or().gt(User::getAge,30);
List<User> users = userDao.selectList(lqw);
System.out.println(users);
}
3.1.2 null判定
查询数据库表中,根据输入年龄范围来查询符合条件的记录
用户在输入值的时候,
如果只输入第一个框,说明要查询大于该年龄的用户
如果只输入第二个框,说明要查询小于该年龄的用户
如果两个框都输入了,说明要查询年龄在两个范围之间的用
@Test
void getNull(){
Integer age1 = 10;
Integer age2 = null;
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//如果 XXX 不为null 则执行
lqw.gt(null!=age1,User::getAge,age1);
lqw.lt(null!=age2,User::getAge,age2);
List<User> users = userDao.selectList(lqw);
System.out.println(users);
}
3.2 查询投影
3.2.1 查询指定字段
查询name和age
@Test
void querySpecifiedField(){
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//通过select来设置查询指定字段名
lqw.select(User::getName,User::getAge);
List<User> users = userDao.selectList(lqw);
System.out.println(users);
}
3.2.2 聚合查询
需求:聚合函数查询,完成count、max、min、avg、sum的使用
count:总记录数
max:最大值
min:最小值
avg:平均值
sum:求和
@Test
void aggregateQuery(){
//聚合函数不能使用Lambda表达式
QueryWrapper<User> qw = new QueryWrapper<>();
//总数
// qw.select("count(*) as count");
//最大年龄
// qw.select("max(age) as maxAge");
//最小年龄
qw.select("min(age) as minAge");
//平均年龄
qw.select("avg(age) as avgAge");
//求和
qw.select("sum(age) as sumAge");
List<Map<String, Object>> maps = userDao.selectMaps(qw);
System.out.println(maps);
}
3.2.3 分组查询
@Test
void getGroup(){
QueryWrapper<User> qw = new QueryWrapper<>();
//根据电话号码分组
qw.select("count(*) as count,tel");
qw.groupBy("tel");
List<Map<String, Object>> maps = userDao.selectMaps(qw);
System.out.println(maps);
}
值得注意的点就是
1.当使用聚合函数和分组查询时不能使用Lambda表达式
2.当涉及到复杂的查询时,MP实现不了可以使用Mybatis的方式进行实现
3.3 条件查询
除开以上的条件查询,MP还封装了大量的查询条件方法
3.3.1 等值查询
根据用户名和密码查询用户信息
@Test
void getUser(){
// 根据用户名和密码查询用户信息
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
lqw.eq(User::getName,"dog").eq(User::getPassword,123456);
User user = userDao.selectOne(lqw);
System.out.println(user);
}
3.3.2 范围查询
@Test
void rangeQuery(){
// 对年龄进行范围查询,使用lt()、le()、gt()、ge()、between()进行范围查询
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//lt是小于 le是小于等于
// lqw.lt(User::getAge,9);
// lqw.le(User::getAge,9);
//gt()是大于 ge()是大于等于
// lqw.gt(User::getAge,9);
// lqw.ge(User::getAge,9);
//between()两者之间
lqw.between(User::getAge,9,30);
List<User> users = userDao.selectList(lqw);
System.out.println(users);
}
3.3.3 模糊查询
@Test
void fuzzyQuery(){
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//两边都加%号
// lqw.like(User::getName,"j");
//左边加%号
// lqw.likeLeft(User::getName,"j");
//右边加%号
lqw.likeRight(User::getName,"j");
List<User> users = userDao.selectList(lqw);
System.out.println(users);
}
3.3.4 排序查询
@Test
void sortQuery(){
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
/**
* condition :条件,返回boolean,
当condition为true,进行排序,如果为false,则不排序
* isAsc:是否为升序,true为升序,false为降序
* columns:需要操作的列
*/
lqw.orderBy(true,false,User::getAge);
List<User> users = userDao.selectList(lqw);
System.out.println(users);
}
运行效果
3.4 映射匹配兼容性
问题1:当表的字段名和实体类的属性名不一致应该怎么办
MybatisPlus 就给我们提供了一个@TableField注解 解决这个问题 value="pwd"
@Data
public class User {
private Long id;
private String name;
@TableField(value = "pwd")
private String password;
private Integer age;
private String tel;
}
问题2:编码中添加了数据库中未定义的属性
我们可以使用@TableField(exist = false) 来解决这个问题
@Data
public class User {
private Long id;
private String name;
@TableField(value = "pwd")
private String password;
private Integer age;
private String tel;
@TableField(exist = false)
private Integer sex;
}
问题3:当我们查询一些一些表中数据时,有些字段是不想被查询到的
我们可以使用select属性来设置
@Data
public class User {
private Long id;
private String name;
@TableField(value = "pwd",select = false)
private String password;
private Integer age;
private String tel;
@TableField(exist = false)
private Integer sex;
}
总结:
@TableField注解
value:设置数据库表字段名称
exist:设置属性在数据库表字段中是否存在,默认为true,此属性不能与value合并使用
select:设置属性是否参与查询,此属性与select()映射配置不冲突
问题4:当表名与实体类名不一样时怎么办?
MP给我们提供了@TableName注解去解决这个问题
@Data
@TableName("tb_user")
public class User {
private Long id;
private String name;
@TableField(value = "pwd",select = false)
private String password;
private Integer age;
private String tel;
@TableField(exist = false)
private Integer sex;
}
四、DML编程控制
4.1 id生成策略控制
@TableId(type = IdType.AUTO)//使用数据库ID自增
-
NONE: 不设置id生成策略
-
INPUT:用户手工输入id
-
ASSIGN_ID:雪花算法生成id(可兼容数值型与字符串型)
-
ASSIGN_UUID:以UUID生成算法作为id生成策略
4.2 多记录操作
根据id批量删除
@Test
void testDelete(){
List<Long> list = new ArrayList<>();
list.add(5l);
list.add(6L);
list.add(7L);
userDao.deleteBatchIds(list);
}
根据id批量查询
@Test
void testSelect(){
List<Long> list = new ArrayList<>();
list.add(1L);
list.add(2L);
list.add(3L);
List<User> users = userDao.selectBatchIds(list);
System.out.println(users);
}
4.3 逻辑删除
问题:当我们需要对某一条数据进行删除,但又不希望该数据走物理上真正的删除,该数据仍然在数据库中进行保留,但查询时却没有该数据
例子:涉及到离职员工的业绩报表
1.我们给数据库添加一列名为 deleted
2.给实体类添加字段名 并添加@TableLogic注解
@Data
@TableName("tb_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
@TableField(value = "pwd",select = false)
private String password;
private Integer age;
private String tel;
@TableField(exist = false)
private Integer sex;
@TableLogic(value = "0",delval = "1")//value是正常数据的值 delval是删除数据的值
private Integer deleted;
}
3.运行删除方法
@Test
void testDelete(){
userDao.deleteById(1L);
}
结果:tom的deleted值已经变为1 且该删除方法实际已经变为update方法
执行的sql如下
我们再执行查询方法看是否还能查询出id=1 的数据
通过日志看到已经没有id为1的数据 且SQL语句增加了一个where deleted=1的条件
4.4 乐观锁
1.给表添加一列 version
2.实体类中添加对应的属性
@Data
@TableName("tb_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
@TableField(value = "pwd",select = false)
private String password;
private Integer age;
private String tel;
@TableField(exist = false)
private Integer sex;
@TableLogic(value = "0",delval = "1")//value是正常数据的值 delval是删除数据的值
private Integer deleted;
@Version
private Integer version;
}
3.添加拦截器
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mpi(){
//1 创建MybatisPlusInterceptor拦截器对象
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//2 添加分页拦截器
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
//3 添加乐观锁拦截器
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
4.执行update方法
@Test
void testUpdate(){
User user = new User();
user.setId(3L);
user.setName("Jock666");
user.setVersion(1);
userDao.updateById(user);
}
5.结果
通过sql语句可以看出
拿到表中的version,然后拿version当条件在将version加1更新回到数据库表中,这样就避免了冲突
五、代码生成器
1.导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.pyh</groupId>
<artifactId>mybatisplus_generator</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatisplus_generator</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!--velocity模板引擎-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.7.RELEASE</version>
<configuration>
<mainClass>com.pyh.MybatisplusGeneratorApplication</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2.创建代码生成类
package com.pyh;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
public class CodeGenerator {
public static void main(String[] args) {
//1.获取代码生成器的对象
AutoGenerator autoGenerator = new AutoGenerator();
//设置数据库相关配置
DataSourceConfig dataSource = new DataSourceConfig();
dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC");
dataSource.setUsername("root");
dataSource.setPassword("123456");
autoGenerator.setDataSource(dataSource);
//设置全局配置
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir(System.getProperty("user.dir")+"/mybatisplus_generator/src/main/java"); //设置代码生成位置
globalConfig.setOpen(false); //设置生成完毕后是否打开生成代码所在的目录
globalConfig.setAuthor("PYH"); //设置作者
globalConfig.setFileOverride(true); //设置是否覆盖原始生成的文件
globalConfig.setMapperName("%sDao"); //设置数据层接口名,%s为占位符,指代模块名称
globalConfig.setIdType(IdType.ASSIGN_ID); //设置Id生成策略
autoGenerator.setGlobalConfig(globalConfig);
//设置包名相关配置
PackageConfig packageInfo = new PackageConfig();
packageInfo.setParent("com.pyh"); //设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径
packageInfo.setEntity("domain"); //设置实体类包名
packageInfo.setMapper("dao"); //设置数据层包名
autoGenerator.setPackageInfo(packageInfo);
//策略设置
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setInclude("tb_user"); //设置当前参与生成的表名,参数为可变参数
strategyConfig.setTablePrefix("tb_"); //设置数据库表的前缀名称,模块名 = 数据库表名 - 前缀名 例如: User = tbl_user - tbl_
strategyConfig.setRestControllerStyle(true); //设置是否启用Rest风格
strategyConfig.setVersionFieldName("version"); //设置乐观锁字段名
strategyConfig.setLogicDeleteFieldName("deleted"); //设置逻辑删除字段名
strategyConfig.setEntityLombokModel(true); //设置是否启用lombok
autoGenerator.setStrategy(strategyConfig);
//2.执行生成操作
autoGenerator.execute();
}
}
3.运行后效果图
该代码也可走官网获取