测试
MyBatis-Plus
官网
https://mp.baomidou.com/
快速入门
- https://mp.baomidou.com/guide/
本质
就是mybatis的升级,只是在mybatis的基础上做了提升,支持完全的向下兼容
这个图可以很好的解释
开始入门Demo
导入依赖
-
;;com.baomidou ;mybatis-plus-boot-starter ;3.0.5 -
只导入这一个依赖,不要再导入mybatis了,避免版本冲突
连接数据库
-
导入mysql依赖
-
;;mysql ;mysql-connector-java
-
-
配置application.properties
-
数据库配置spring.datasource.url=jdbc:mysql://localhost:3306/sbs?useSSL=falseamp;useUnicode=trueamp;characterEncoding=utf-8amp;serverTimezone=UTCspring.datasource.username=root # 时区配置,mysql8必须配置spring.datasource.password=rootspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # 这是mysql8的版本驱动,完全支持向下兼容
-
编写pojo类
- package com.xiaoye.entity;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import java.time.LocalDateTime;/** * @author 小也 * @create 2021/4/22 13:53 */@Data@AllArgsConstructor@NoArgsConstructorpublic class SysUser { private Long id; private String username; private String password; private String nickname; private Long gender; private Long age; private Long clazzId; private Long isDelete; private Long version; private LocalDateTime bjtCreate; private LocalDateTime bjtModified; }
编写mapper接口
-
package com.xiaoye.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.xiaoye.entity.SysUser;import org.apache.ibatis.annotations.Mapper;/** * @author 小也 * @create 2021/4/22 13:56 */@Mapperpublic interface SysUserMapper extends BaseMapper
; { //只要集成了BaseMapper这个父类就可以直接使用很多的单表操作了 } -
BaseMapper
- //// Source code recreated from a .class file by IntelliJ IDEA// (powered by FernFlower decompiler)//package com.baomidou.mybatisplus.core.mapper;import com.baomidou.mybatisplus.core.conditions.Wrapper;import com.baomidou.mybatisplus.core.metadata.IPage;import java.io.Serializable;import java.util.Collection;import java.util.List;import java.util.Map;import org.apache.ibatis.annotations.Param;public interface BaseMapper
; { int insert(T var1); int deleteById(Serializable var1); int deleteByMap(@Param("cm") Map ; var1); int delete(@Param("ew") Wrapper ; var1); int deleteBatchIds(@Param("coll") Collection<? extends Serializable>; var1); int updateById(@Param("et") T var1); int update(@Param("et") T var1, @Param("ew") Wrapper ; var2); T selectById(Serializable var1); List ; selectBatchIds(@Param("coll") Collection<? extends Serializable>; var1); List ; selectByMap(@Param("cm") Map ; var1); T selectOne(@Param("ew") Wrapper ; var1); Integer selectCount(@Param("ew") Wrapper ; var1); List ; selectList(@Param("ew") Wrapper ; var1); List
- //// Source code recreated from a .class file by IntelliJ IDEA// (powered by FernFlower decompiler)//package com.baomidou.mybatisplus.core.mapper;import com.baomidou.mybatisplus.core.conditions.Wrapper;import com.baomidou.mybatisplus.core.metadata.IPage;import java.io.Serializable;import java.util.Collection;import java.util.List;import java.util.Map;import org.apache.ibatis.annotations.Param;public interface BaseMapper
-
在主启动类上扫描mapper接口
- package com.xiaoye;import org.mybatis.spring.annotation.MapperScan;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;/** * @author 22944 */@SpringBootApplication@MapperScan("com.xiaoye.mapper")public class Springboot04MybatisPlusApplication { public static void main(String[] args) { SpringApplication.run(Springboot04MybatisPlusApplication.class, args); }}
开启mybatis-plus的日志
-
配置application.properties配置文件
-
开启日志输出mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
-
测试一波
-
测试代码
- package com.xiaoye;import com.baomidou.mybatisplus.core.conditions.Wrapper;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.xiaoye.entity.SysUser;import com.xiaoye.mapper.SysUserMapper;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import java.util.List;@SpringBootTestclass Springboot04MybatisPlusApplicationTests { @Autowired private SysUserMapper sysUserMapper; @Test void contextLoads() { QueryWrapper
; wrapper = new QueryWrapper<>;(); wrapper.eq("id",1).like("nickname","ye").le("age",30).ge("gender","1"); List ; users = sysUserMapper.selectList(wrapper); for (SysUser user : users) { System.out.println(user.toString()); } }}
- package com.xiaoye;import com.baomidou.mybatisplus.core.conditions.Wrapper;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.xiaoye.entity.SysUser;import com.xiaoye.mapper.SysUserMapper;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import java.util.List;@SpringBootTestclass Springboot04MybatisPlusApplicationTests { @Autowired private SysUserMapper sysUserMapper; @Test void contextLoads() { QueryWrapper
-
QueryWrapper
-
QueryWrapper是mybatis-plus自带的条件查询器,我们可以使用这个QueryWrapper来构造查询条件
-
eq("数据库列名","值")
- 要求某行的该列值和传入的值完全相等才能查出来
-
like("数据库列名","值")
- 要求某行的该列值包含传入的值才能查出来
-
le("数据库列名","值")
- 要求某行的该列值小于等于传入的值才能查出来
-
ge("数据库列名","值")
- 要求某行的该列值大于等于传入的值才能查出来
-
-
测试结果
- mybatis-plus会帮我们自动生成简单的sql并拼接,对于单表操作可以说很友好了,但是对于多表联查还是需要自己手动写的
乐观锁
简介
- 当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
实际操作一下
-
实体类中需要在相对应得字段上添加@Version注解
-
编写配置类(来自官网)
- // Spring Boot 方式@Configuration@MapperScan("按需修改")public class MybatisPlusConfig { /** * 旧版 / @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); } /* * 新版 */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mybatisPlusInterceptor; }}
-
测试乐观锁
-
普通情况下(单线程操作)
-
@Test void OptimisticLockTest(){ //1、查询用户,拿到版本号 SysUser user = sysUserMapper.selectById(1); //2、执行更新操作 user.setAge(18); sysUserMapper.updateById(user); } -
结果
-
-
多线程情况下
-
@Test void OptimisticLockTest(){ //线程A SysUser user1 = sysUserMapper.selectById(1); user1.setAge(18); //线程B执行 SysUser user2 = sysUserMapper.selectById(1); user2.setAge(30); sysUserMapper.updateById(user2); //线程A继续执行更新操作 sysUserMapper.updateById(user1); } -
结果
-
-
分页查询
我们首先想到的应该是学过的limit关键字,在数据库层面实现分页查询
现在我们使用mybatis-plus自带的分页插件来实现分页查询
简单的Page实现
-
代码
-
@Test void limitPageTest(){ Page; page = new Page<>;(2,1); sysUserMapper.selectPage(page,null); page.getRecords().forEach(System.out::println); }
-
-
效果
- 一共三条记录,现在显示页面大小为1,第二页的记录
自动代码生成
AutoGenerator类
可能报错
-
导入依赖即可
-
;;org.apache.velocity ;velocity-engine-core ;2.0
-
源码
- package com.xiaoye.util;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;/** * @author 小也 * @create 2021/4/22 19:37 */public class AutoCoding { private static final String DATA_SOURCE_DRIVER = "com.mysql.cj.jdbc.Driver"; private static final String DATA_SOURCE_URL = "jdbc:mysql://localhost:3306/sbs?useSSL=falseamp;useUnicode=trueamp;characterEncoding=utf-8amp;serverTimezone=UTC"; private static final String DATA_SOURCE_USERNAME = "root"; private static final String DATA_SOURCE_PASSWORD = "root"; private static final String MODULE_NAME = "sys"; private static final String MODULE_PARENT_NAME = "com.xiaoye"; private static final String TABLE_NAME = "sys_user"; private static final String LOGIC_DELETE_NAME = "is_delete"; private static final String GMT_CREATE = "bjt_create"; private static final String GMT_MODIFIED = "bjt_modified"; private static final String OPTIMISTIC_LOCK_NAME = "version"; public static void main(String[] args) { //创建自动代码生成对象 AutoGenerator autoGenerator = new AutoGenerator(); //1、全局配置 GlobalConfig globalConfig = new GlobalConfig(); //设置作者 globalConfig.setAuthor("xiaoye"); //获取当前项目路径 String properties = System.getProperty("user.dir"); //设置输出路径 globalConfig.setOutputDir(properties + "/src/main/java"); //不要打开资源管理器 globalConfig.setOpen(false); //不覆盖原文件 globalConfig.setFileOverride(false); //service接口不带I前缀 globalConfig.setServiceName("%sService"); //设置id自增 globalConfig.setIdType(IdType.AUTO); //设置时间格式 globalConfig.setDateType(DateType.TIME_PACK); //配置swagger2文档 globalConfig.setSwagger2(true); //设置mapper.xml生成一个RestMap globalConfig.setBaseResultMap(true); autoGenerator.setGlobalConfig(globalConfig); //2、数据源配置 DataSourceConfig dataSourceConfig = new DataSourceConfig(); dataSourceConfig.setDbType(DbType.MYSQL); dataSourceConfig.setDriverName(DATA_SOURCE_DRIVER); dataSourceConfig.setUrl(DATA_SOURCE_URL); dataSourceConfig.setUsername(DATA_SOURCE_USERNAME); dataSourceConfig.setPassword(DATA_SOURCE_PASSWORD); autoGenerator.setDataSource(dataSourceConfig); //3、生成包配置 PackageConfig packageConfig = new PackageConfig(); packageConfig.setModuleName(MODULE_NAME); packageConfig.setParent(MODULE_PARENT_NAME); packageConfig.setEntity("entity"); packageConfig.setMapper("mapper"); packageConfig.setService("service"); packageConfig.setController("controller"); autoGenerator.setPackageInfo(packageConfig); //4、策略配置 StrategyConfig strategyConfig = new StrategyConfig(); //要映射的表名 strategyConfig.setInclude(TABLE_NAME); //下划线转驼峰命名 strategyConfig.setNaming(NamingStrategy.underline_to_camel); //下划线转驼峰命名 strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel); //开启lombok strategyConfig.setEntityLombokModel(true); //开启逻辑删除名字 strategyConfig.setLogicDeleteFieldName(LOGIC_DELETE_NAME); //自动填充设置 TableFill bjtCreate = new TableFill(GMT_CREATE, FieldFill.INSERT); TableFill bjtModified = new TableFill(GMT_MODIFIED, FieldFill.INSERT_UPDATE); ArrayList
; tableFieldList = new ArrayList<>;(); tableFieldList.add(bjtCreate); tableFieldList.add(bjtModified); strategyConfig.setTableFillList(tableFieldList); //乐观锁配置 strategyConfig.setVersionFieldName(OPTIMISTIC_LOCK_NAME); //restFul风格 strategyConfig.setRestControllerStyle(true); //下划线url strategyConfig.setControllerMappingHyphenStyle(true); autoGenerator.setStrategy(strategyConfig); //开始执行代码生成 autoGenerator.execute(); }}
主键自增
数据库明明设置了主键自增,为什么添加数据的时候却给了一串很长的随机数呢?
其实这是mybatis-plus帮我们生成的主键id,采用的是twitter的雪花算法,用毫秒数、机器编号等参数形成的唯一id
我们想要变成我们想要的1,2,3,4,5这种简单的自增也很简单,添加一个注解就好了
时间戳
阿里巴巴Java开发手册上明确表示了数据库建表的时候必须要有创建时间(gmt_create)、修改时间(gmt_modified)字段
我们来实际使用一下
-
数据库建表加上这两个字段,并且类型设置timestamp
-
创建时间
- 默认时现在操作的时间,并且不再更新
-
修改时间
- 默认是现在的操作时间,并且会因为数据更新而更新时间戳
-
上面的操作在数据库中操作以及完全可以玩的来了,但是实际开发我却发现更新不生效
所以我查了很多资料,发现解决方式有两种,一种是加注解,一种是加注解和配置类
既然一个注解可以解决的事情,我为什么还要加配置类呢?完事收工
逻辑删除
之前写逻辑删除的时候每次写sql都要手动拼接is_delete = 0,现在mybatis-plus帮我们封装好了
逻辑删除字段添加注解
-
@TableLogic private Integer isDelete;
配置拦截器
- package com.xiaoye.config;import com.baomidou.mybatisplus.core.injector.ISqlInjector;import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;import org.mybatis.spring.annotation.MapperScan;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * @author 小也 * @create 2021/4/22 16:40 /@MapperScan("com.xiaoye.mapper")@Configurationpublic class MybatisPlusConfig { /* * 乐观锁 * @return / @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor(){ return new OptimisticLockerInterceptor(); } /* * 分页组件 * @return / @Bean public PaginationInterceptor paginationInterceptor(){return new PaginationInterceptor();} /* * 逻辑删除 * @return */ @Bean public ISqlInjector iSqlInjector(){return new LogicSqlInjector();}}
application.properties配置文件里配置逻辑删除的代号
-
开启日志输出mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl#逻辑删除,未删除是0,已删除是1mybatis-plus.global-config.db-config.logic-not-delete-value=0mybatis-plus.global-config.db-config.logic-delete-value=1
开始测试
-
测试代码
-
@Test void logicDeleteTest(){ sysUserMapper.deleteById(1); }
-
-
测试结果
- 先执行删除操作
- 再次查询发现已经查不到了
- 我们可以通过navicat看到实际上只是更改了is_delete的值,并没有真的删除
性能分析插件
性能分析插件就是记录每条sql执行的时间,超时就会停止运行
导入插件,注册组件
-
@Bean public PerformanceInterceptor performanceInterceptor(){ PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor(); //这里是毫秒数,设置sql执行的最大时间,超时就停止 performanceInterceptor.setMaxTime(100); //开启sql格式化 performanceInterceptor.setFormat(true); return performanceInterceptor; }
开始测试
- 这个很常用,可以有效找到慢查询