Mybatis-Plus学习
目录1. mybatisplus概述1.1 特性1.2 快速入门1.3 配置日志1.4 CRUD扩展1.4.1 insert插入1.4.2 主键生成策略1.4.3 更新操作1.4.4 自动填充1.4.5 乐观锁1. mybatisplus概述官方文档:链接mybatisplus是一个mybatis的增强工具,在mybatis的基础上只做增强不做改变,为简化开发、提高效率而生。1.1 特性1.2 快
1. mybatisplus概述
官方文档:链接
mybatisplus是一个mybatis的增强工具,在mybatis的基础上只做增强不做改变,为简化开发、提高效率而生。
1.1 特性
1.2 快速入门
1.先建个数据库mybatisplus,然后执行下面代码建表
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
然后建个springboot项目
2.导入对应的依赖:
<!--MySQL驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!-- 可通过version设置版本号 -->
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- mybatisplus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
说明:使用 mybatisplus 可以节省我们大量的代码,但尽量不要同时导入mybatis 和 mybatisplus!会有版本的差异!
3.连接数据库,与mybatis一样
# 数据库8.版本需要加上cj
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
4.编写测试
传统编写方式: pojo-dao(连接mybatis,配置mapper.xml文件)-service-controller
使用了mybatisplus之后:
-
pojo
-
mapper接口
User代表对应的实体类,实体类对应到数据库表名!
不要忘记在主启动类上扫描我们的mapper包下的所有接口:@MapperScan("com.liu.mapper") //扫描mapper文件夹
-
使用
1.3 配置日志
我们所有的sql现在不可见的,因此若想知道它是怎么执行的必须要看日志!
在核心配置文件中:
# 配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
配置完毕日志之后,后面的学习就需要注意这个自动生成得SQL
1.4 CRUD扩展
1.4.1 insert插入
数据库插入的id的默认值:全局的唯一id
1.4.2 主键生成策略
雪花算法生成的id几乎可以保证全球唯一
这里先说三个注解:都是当与数据库中的名字不能按照驼峰对应上时需要用。
@TableName(value=“”):映射数据库表名
@TableId(value=“”):映射数据库表主键
@TableField(value=“”):映射数据库表非主键属性
通过注解的方式可设置生成的id。
下面是几种方式:
- ID_WORKER:全局唯一ID(默认)
- AUTO:主键递增
- 需要在实体类字段上配置@TableId(type = IdType.AUTO)
- 数据库字段一定要是递增的
- 再次进行插入操作发现id号比原来加1,现在是递增的!
- INPUT:手动输入id
在实体类字段上配置:@TableId(type = IdType.INPUT)
- 其余的取值解释
1.4.3 更新操作
所有的sql都是自动帮你动态配置的!
1.4.4 自动填充
创建时间、修改时间 这些操作一般都是自动化完成的,不需要手动更新!
阿里巴巴开发手册:所有的数据库表:gmt_create、gmt_modified几乎所有的表都要配置上!而且需要自动化!
-
在数据库中user表添加两个属性 create_time 和 update_time
-
然后在实体类字段属性上添加注解
-
编写处理器来处理这个注解
-
测试插入、观察时间
-
测试更新、观察时间
1.4.5 乐观锁
乐观锁:顾名思义十分乐观,它总是认为不会出现问题,无论干什么都不去上锁!如果出现了问题,再更新值测试。
悲观锁:顾名思义十分悲观,它总是认为会出现问题,无论干什么都会上锁,然后再去操作!
乐观锁实现方式:
- 取出记录时,获取当前 version
- 更新时,带上这个 version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果 version 不对,就更新失败
实现过程:
-
在数据库中加入version属性,先全赋值为1
-
在实体类version字段添加注解
-
编写配置类
这里要注意,采用了新版的乐观锁插件,需要添加依赖:<!-- 新版乐观锁依赖 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.0</version> </dependency>
-
测试
首先是单线程,一定能修改成功!
然后是多线程,前者修改失败!
最后更新是222,没有让111覆盖掉!
1.4.6 查询操作
测试批量查询:
测试条件查询:
1.4.7 分页查询
首先在配置类中配置分页插件
然后直接使用Page对象即可
1.4.8 删除操作
普通删除
批量删除
通过map条件删除
1.4.9 逻辑删除
物理删除:从数据库直接移除
逻辑删除:在数据库中没有被移除,而是通过一个变量来让它失效!deleted=0 => deleted=1
管理员可以查看被删除的记录,用户删除时应用的就是逻辑删除。用于防止数据的丢失,类似于回收站。
1、在数据库表中增加一个字段deleted(注意不能为delete),默认为0
2、实体类中增加属性
3、在核心配置文件中配置
4、测试使用
执行删除操作
然后我们再执行查询操作发现查询条件自动判断deleted。已查询不到数据
1.4.10 性能分析插件
1、先导入依赖
<!-- 新版性能分析依赖 -->
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>3.9.1</version>
</dependency>
2、然后修改核心配置文件
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.datasource.url=jdbc:mysql://localhost:3306/mybatisplus?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8
# 上面是原先的配置,更改为下方的新版性能分析的配置
spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver
spring.datasource.url=jdbc:p6spy:mysql://localhost:3306/mybatisplus?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8
3、新建spy.properties配置文件,并编写内容
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
4、测试
1.4.11 条件构造器Wrapper
1.4.11.1 查询
方式一:new QueryWrapper 或者 new LambdaQueryWrapper
带上Lambda是方便书写查询条件时用lambda表达式。
这种条件适合于查询条件不是一下写完的,经过一些判断分开写的。
QueryWrapper<实体> wrapper = new QueryWrapper<>();
wrapper.lambda().eq().... // 加lambda()是后面方便使用lambda表达式,比如 .eq(User::getUserId, "")
测试一:
测试二:
测试三(between查询):
测试四(模糊查询):
测试五(子查询):
测试六(排序):
方式二:Wrappers.<实体>lambdaQuery()用法(推荐)
(这种方式更简洁,适合于一次性将所有条件写完)
还可以 Wrappers.lambdaQuery(实体.class) ,一样的。
sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
.eq(SysUser::getAccount, username)
.eq(SysUser::getMobile, mobile));
sql语句为:
select * from sys_user where account = #{username} and mobile = #{mobile};
1.4.11.2 更新
同查询,也是两种方式。
方式一:
方式二:
Wrappers.lambdaUpdate <实体.class> 用法
1.4.11.3 删除
wrapper 与查询时类似。
1.4.12 代码自动生成器(下面有通过MybatisCodeHelperPro插件实现的,更简单)
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
1、设置配置类
2、设置核心配置文件,还有用于性能分析的spy.properties(可选)。
# 数据库连接配置
# 数据库8.版本需要加上cj
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.datasource.url=jdbc:mysql://localhost:3306/mybatisplus?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8
# 新版性能分析的配置
spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver
spring.datasource.url=jdbc:p6spy:mysql://localhost:3306/mybatisplus?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
# 配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 逻辑删除,逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值(默认为 0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0
3、新建一个类,这里是在测试文件夹下建的类:
package com.liu;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
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;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.ArrayList;
//代码自动生成器
public class LiuCode {
public static void main(String[] args) {
//我们需要构建一个代码生成器对象
AutoGenerator mpg = new AutoGenerator();
//怎么样去执行,配置策略
//1、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");//获取当前目录
gc.setOutputDir(projectPath+"/src/main/java");//输出到哪个目录
gc.setAuthor("liu");
gc.setOpen(false);
gc.setFileOverride(false);//是否覆盖
gc.setServiceName("%sService");//去Service的I前缀
gc.setIdType(IdType.ID_WORKER);
gc.setDateType(DateType.ONLY_DATE);
gc.setSwagger2(true);
mpg.setGlobalConfig(gc);
//2、设置数据源
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUsername("root");
dsc.setPassword("root");
dsc.setUrl("jdbc:mysql://localhost:3306/mybatisplus?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
//3、包的配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("study");
pc.setParent("com.liu");
pc.setEntity("pojo");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc); // 在com.liu.study包下生成pojo、mapper、service、controller这些包
//4、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("user");//设置要映射的表名,只需改这里即可! 即自动生成数据库中的哪些表!
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);//是否使用lombok开启注解
strategy.setLogicDeleteFieldName("deleted");
//自动填充配置
TableFill gmtCreate = new TableFill("create_time", FieldFill.INSERT);
TableFill gmtUpdate = new TableFill("update_time", FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills = new ArrayList<>();
tableFills.add(gmtCreate);
tableFills.add(gmtUpdate);
strategy.setTableFillList(tableFills);
//乐观锁配置
strategy.setVersionFieldName("version");
strategy.setRestControllerStyle(true);//开启驼峰命名
strategy.setControllerMappingHyphenStyle(true);//localhost:8080/hello_id_2
mpg.setStrategy(strategy);
mpg.execute();//执行
}
}
4、添加依赖:
<dependencies>
<!--MySQL驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!-- 可通过version设置版本号 -->
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- mybatisplus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<!-- 新版乐观锁依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.0</version>
</dependency>
<!-- 新版性能分析依赖 -->
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>3.9.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--模板引擎 依赖:mybatis-plus代码生成的时候报异常-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
<!--配置ApiModel在实体类中不生效-->
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>spring-boot-starter-swagger</artifactId>
<version>1.5.1.RELEASE</version>
</dependency>
<!--freemarker-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
<!--beetl-->
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetl</artifactId>
<version>3.3.2.RELEASE</version>
</dependency>
</dependencies>
5、运行LiuCode类即可!
1.5 Mybatis-Plus 练习
1.5.0 插件自动根据数据库表生成po、mapper、mapper.xml
1、IDEA连接到数据库
2、在将要生成的表右键 --> Mybatis generator
3、做如下配置:
在弄一下最下面的 mybatisPlus配置
其他的配置都可以不用配,默认方法也全不勾,用处不大。
生成:
po实体类:
mapper接口:
mapper.xml:
1.5.1 普通单表查询
注意:Wrappers.lambdaQuery(.class) 这个类型必须是主表的类型,即查询返回的结果必须是主表的类型。想转为VO的话自己再做处理。
在设置条件语句时,第一个参数可以加一个判空条件,当不为空时条件才生效!
1.5.1.1 .and() .or() 语句实现复杂逻辑
如果传来的一个值是模糊查询,可能是表中某多个字段的取值。这个时候对传来的模糊查询值判空后,就需要用 or 来检查是哪个字段的取值。
此时应这样写:
用 .and 来扩上,也就是 A and ( B or C ),不用 .and 的话就变成了 A and B or C,就错了。
sql语句为:
1.5.2 单表分页查询
1.5.3 连表查询
引入join依赖:
<!-- mpj -->
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-boot-starter</artifactId>
<version>1.3.8</version>
</dependency>
将发起连表的那个表Mapper 继承自 MPJBaseMapper< PersonInfo>
然后就可以使用了,连表查询代码如下:
// PersonInfo表 左连接 PersonMobile表
MPJLambdaWrapper<PersonInfo> wrapper = new MPJLambdaWrapper<PersonInfo>()
.selectAll(PersonInfo.class) // 选择 PersonInfo的所有字段
// .select(PersonMobile::getMobile) // 选择PersonMobile某一字段
.selectAs(PersonMobile::getMobile, PersonInfoVO::getPersonMobile) // 选择PersonMobile某一字段,并改名与自定义返回给前端的VO中的字段名字对应
.leftJoin(PersonMobile.class, PersonMobile::getName, PersonInfo::getName) // 两表左连接,根据Name连接
.eq(PersonInfo::getAge, 18) // 年龄=18
.likeRight(PersonInfo::getName, "康"); // 康%,即以康开头
List<PersonInfoVO> list = personInfoMapper.selectJoinList(PersonInfoVO.class, wrapper);
list.forEach(t->{
System.out.println(t);
});
1.5.4 连表分页查询
// PersonInfo表 左连接 PersonMobile表
MPJLambdaWrapper<PersonInfo> wrapper = new MPJLambdaWrapper<PersonInfo>()
.selectAll(PersonInfo.class) // 选择 PersonInfo的所有字段
// .select(PersonMobile::getMobile) // 选择PersonMobile某一字段
.selectAs(PersonMobile::getMobile, PersonInfoVO::getPersonMobile) // 选择PersonMobile某一字段,并改名与自定义返回给前端的VO中的字段名字对应
.leftJoin(PersonMobile.class, PersonMobile::getName, PersonInfo::getName) // 两表左连接,根据Name连接
.eq(PersonInfo::getAge, 18) // 年龄=18
.likeRight(PersonInfo::getName, "康"); // 康%,即以康开头
Page<PersonInfoVO> page = new Page<>(1,3);
List<PersonInfoVO> list = personInfoMapper.selectJoinPage(page, PersonInfoVO.class, wrapper).getRecords();
list.forEach(t->{
System.out.println(t);
});
1.5.5 更新操作
personInfoMapper.update(null, Wrappers.lambdaUpdate(PersonInfo.class)
// .set(PersonInfo::getAge, 20) // 直接设置值
.setSql("age = age + 5") // 在原有值的基础上设置值
.le(PersonInfo::getAge, 15)); // 条件
1.5.6 实现包含数据库特定函数的分组查询
下面是 QueryWrapper 的实现,用 LambdaQueryMapper 不方便。 感觉还是 XML 更方便
QueryWrapper<DemandUserDemand> queryWrapper = new QueryWrapper<>();
queryWrapper.select("MONTH(create_time) as month", "COUNT(*) as demandNum")
.eq("YEAR(create_time)", Year.now().getValue())
.groupBy("MONTH(create_time)")
.orderByAsc("MONTH(create_time)");
对于一些简单的查询,LambdaQueryWrapper 可能更加直观和方便,而对于一些复杂的查询,可能需要使用 XML 来实现。另外,对于一些数据库特定的函数,如获取月份、日期加减等操作,使用 XML 可能更加直接和方便。
更多推荐
所有评论(0)