- 1.简介
- 1.1、特性
- 2.快速开始
- 3.配置日志
- 4.CRUD拓展
- 4.1、插入
- 4.2、更新
- 4.3、查询
- 4.4、删除
- 5.性能分析插件
- 6.条件构造器Wrapper
- 7.代码生成器
- 8.配置文件
1.简介
MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
1.1、特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 – Sequence),可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
2.快速开始
- 创建数据库mybatis_plus
- 创建表user
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');
- 创建项目并初始化!!
- 导入依赖
com.baomidou
mybatis-plus-boot-starter
3.5.2
注:尽量不要同时导入mybatis和mybatis-plus依赖,可能会产生冲突
6. 配置数据源
spring:
datasource:
username: root
password: 18227022334a
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
- 在对应的UserMaaper接口上继承BaseMapper
@Repository
public interface UserMapper extends BaseMapper {
}
注:
– 不需要再去配置xml文件,所有基本的查询语句是在BaseMapper接口中了!!,基本的CRUD以已经实现,但是如果有特殊的sql语句,还是需要自己编写!!
– 需要在继承的BaseMaaper传入pojo的实体类泛型
8. 测试
@SpringBootTest
class MybatisPlusStudyApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
List userList = userMapper.selectList(null);
for (User user : userList) {
System.out.println(user);
}
}
}
注:UserMapper 中的 selectList()
方法的参数为 MP 内置的条件封装器 Wrapper
,所以不填写就是无任何条件
3.配置日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
4.CRUD拓展
4.1、插入
- 在插入数据的时候,如果主键id我们没有自己设定,那么会自动生成一个全局唯一的id,并且会自动回填到我们的对象里面,也就是会自动将我们原本没有设置id的对象的id赋值!!
- 主键生成策略:
- 参考博客:
- UUID
- 自增ID
- 雪花算法(默认):使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0,每次生成唯一的值
- Redis
- zookeeper
- 配置主键生成策略:
public class User {
@TableId(type = IdType.ASSIGN_ID)//默认
private Long id;
private String name;
private Integer age;
private String email;
}
IdType:值 描述 AUTO 数据库 ID 自增 NONE 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT) INPUT insert 前自行 set 主键值 ASSIGN_ID 分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口 IdentifierGenerator
的方法 nextId
(默认实现类为 DefaultIdentifierGenerator
雪花算法) ASSIGN_UUID 分配 UUID,主键类型为 String(since 3.3.0),使用接口 IdentifierGenerator
的方法 nextUUID
(默认 default 方法) ID_WORKER 分布式全局唯一 ID 长整型类型(please use ASSIGN_ID
)(弃用) UUID 32 位 UUID 字符串(please use ASSIGN_UUID
)(弃用) ID_WORKER_STR 分布式全局唯一 ID 字符串类型(please use ASSIGN_ID
)(弃用) 注:使用自增的话如果不成功可能跟数据库没有勾选自增选项有关!!
4.2、更新
- 更新的时候虽然名字是ById,但是需要传入的是一个适配的泛型类对象,同时通过日志可以发现,mybatis-plus会根据条件自动帮我们拼接sql语句,即加入某一字段值为空,那么设置的时候就不会set该字段!!
- 自动填充
- 阿里巴巴开发手册表明,所有的数据库表都应该包含的两个字段:gmt_create,gmt_modified,也就是创建时间以及修改时间,而有关这个的操作,我们都应该使用自动化来完成!!
- 数据库级别操作(实际工作不被允许):使用默认值的方式
- 代码级别:
- 使用@TableField(fill=…)注解
//@TableField(fill = FieldFill.DEFAULT) 默认
//有以下值:DEFAULT, INSERT,UPDATE,INSERT_UPDATE;
@TableField(fill = FieldFill.INSERT)
private Data gmtCreate;//mybatis-plus自动开启驼峰命名
@TableField(fill = FieldFill.INSERT_UPDATE)
private Data gmtModified;
+ 编写自定义实现类 MyMetaObjectHandler处理这个注解
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
//插入时自动填充策略
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill......");
this.setFieldValByName("gmtCreate",LocalDateTime.now(),metaObject);
this.setFieldValByName("gmtModified",LocalDateTime.now(),metaObject);
}
//更新时自动填充策略
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill......");
this.setFieldValByName("gmtModified", LocalDateTime.now(),metaObject);
}
}
+ 测试!!
+ 注:当数据类型为long时,应该在数据后面加上l表示数据为长整数!!
- 乐观锁悲观锁
- 乐观锁:十分乐观,总是认为不会出现问题,无论干什么都不会上锁,如果出现问题再次进行各更新值测试!
- 悲观锁:十分悲观,总是认为干什么都会出现问题,无论干什么都会上锁,在去操作!
- 当要更新一条记录的时候,希望这条记录没有被别人更新,乐观锁实现方式:
- 取出记录时,获取当前 version
- 更新时,带上这个 version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果 version 不对,就更新失败
- 说明:
- 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 整数类型下
newVersion = oldVersion + 1
newVersion
会回写到entity
中- 仅支持
updateById(id)
与update(entity, wrapper)
方法 - 在
update(entity, wrapper)
方法下,wrapper
不能复用!!!
- 实现乐观锁:
- 数据库添加字段version
- 实体类添加属性
@Version
private Integer version;
3. 新建一个配置类配置插件
@Configuration
@MapperScan("com.xiaoye.mapper")//可以不用放在启动类上,也可以放在这里
@EnableTransactionManagement//自动管理事务
public class MyBatisPlusConfig {
//注册乐观锁插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
4. 测试!!
4.3、查询
- 常用查询:
- selectById():根据id查询
- selectList():查询全部
- selectBatchIds():批量查询,参数是一个集合
- selectByMap():条件查询,参数为map,map的键为字段名,值为字段值
- 分页查询:
- 在配置类下增加插件
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor2() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
- 使用
void contextLoads() {
//第一个参数:当前页
//第二个参数:页面个数
Page userPage = new Page<>(2,3);
userMapper.selectPage(userPage, (Wrapper) null);
for (User record : userPage.getRecords()) {
System.out.println(record);
}
}
///userPage.getTotal()得到数据总数
4.4、删除
- 常用删除:
//
userMapper.delete();
//批量删除
userMapper.deleteBatchIds();
//根据id删除
userMapper.deleteById();
//根据条件删除
userMapper.deleteByMap();
- 逻辑删除:在数据库中不直接删除,而是通过一个逻辑变量,比如is_delete=0|1,而不是真正的删除 补充说明:
- 只对自动注入的 sql 起效:
- 插入: 不作限制
- 查找: 追加 where 条件过滤掉已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段
- 更新: 追加 where 条件防止更新到已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段
- 删除: 转变为 更新
- 在数据库增加一个is_delete字段
- 在实体类中增加属性(3.3以后可以不用加注解)
@TableLogic
private Integer isDelete;
- 在yaml中配置
mybatis-plus:
global-config:
db-config:
logic-delete-field: isDelete # 全局逻辑删除的实体字段名
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
- 测试!!
- 常见问题:
- 如何插入:
- 数据库定义默认值(推荐)
- 自己set
- 使用自动填充功能
- 删除接口功能自动填充功能失效:
- 使用
deleteById
方法(推荐) - 使用
update
方法并:UpdateWrapper.set(column, value)
(推荐) - 使用
update
方法并:UpdateWrapper.setSql("column=value")
5.性能分析插件
该功能依赖 p6spy
组件,完美的输出打印 SQL 及执行时长
- 导入依赖:
p6spy
p6spy
3.2.0
- application.yaml更改数据库方方面的配置
username: root
password: 18227022334a
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
- 配置spy.properties
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
自定义日志打印
logMessageFormat=com.xiaoye.log.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
- 编写自定义日志类
@Slf4j
public class P6SpyLogger implements MessageFormattingStrategy {
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql) {
String date = dateFormat.format(new Date());
if (log.isInfoEnabled()) {
log.info("执行时间: {}", date);
log.info("sql: {}", sql);
log.info("耗时:{} 毫秒", elapsed);
}
return "";
}
}
- 注意:
- driver-class-name 为 p6spy 提供的驱动类
- url 前缀为 jdbc:p6spy 跟着冒号为对应数据库连接地址
- 打印出 sql 为 null,在 excludecategories 增加 commit
- 批量操作不打印 sql,去除 excludecategories 中的 batch
- 批量操作打印重复的问题请使用 MybatisPlusLogFactory (3.2.1 新增)
- 该插件有性能损耗,不建议生产环境使用。
6.条件构造器Wrapper
- QueryWrapper:select,delete使用
- UpdateWrapper:update使用
- 可以使用链式编程:
public void test1(){
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.gt("age",21).like("name","李");
List userList = userMapper.selectList(wrapper);
userList.forEach(System.out::println);
}
7.代码生成器
- 导入依赖
com.baomidou
mybatis-plus-boot-starter
3.5.2
com.baomidou
mybatis-plus-generator
3.5.2
org.apache.velocity
velocity
1.7
- 编写自动生成代码类
package com.xiaoye;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.IFill;
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.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.fill.Column;
import com.baomidou.mybatisplus.generator.fill.Property;
import java.util.ArrayList;
import java.util.List;
public class Test{
private static final DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder("jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC", "root", "18227022334a")
.build();
public static void main(String[] args) {
/**
* 代码生成
*/
GlobalConfig globalConfig = new GlobalConfig.Builder()
.author("小也")
.dateType(DateType.TIME_PACK)
.commentDate("yyyy-MM-dd hh:mm:ss")
.outputDir(System.getProperty("user.dir") + "/src/main/java")
.build();
PackageConfig packageConfig = new PackageConfig.Builder()
.parent("com.xiaoye")
.entity("pojo")
.service("service")
.serviceImpl("service.Impl")
.mapper("mapper")
.xml("mapper.xml")
.controller("controller")
.build();
StrategyConfig strategyConfig = new StrategyConfig.Builder()
.entityBuilder()
.enableTableFieldAnnotation()
.enableLombok()
.enableTableFieldAnnotation()
.versionColumnName("version")
.versionPropertyName("version")
.logicDeleteColumnName("is_delete")
.logicDeletePropertyName("isDelete")
.columnNaming(NamingStrategy.underline_to_camel)
.addTableFills(new Column("gmt_create", FieldFill.INSERT))
.addTableFills(new Column("gmt_modified", FieldFill.INSERT))
.addTableFills(new Property("gmtCreate", FieldFill.INSERT_UPDATE))
.addTableFills(new Property("gmtModified", FieldFill.INSERT_UPDATE))
.build();
StrategyConfig strategyConfig1 = new StrategyConfig.Builder()
.controllerBuilder()
.enableHyphenStyle()
.enableRestStyle()
.build();
StrategyConfig strategyConfig2 = new StrategyConfig.Builder()
.serviceBuilder()
.build();
StrategyConfig strategyConfig3 = new StrategyConfig.Builder()
.mapperBuilder()
.enableMapperAnnotation()
.enableBaseResultMap()
.enableBaseColumnList()
.build();
AutoGenerator generator = new AutoGenerator(dataSourceConfig);
generator.global(globalConfig);
generator.strategy(strategyConfig);
generator.strategy(strategyConfig1);
generator.strategy(strategyConfig2);
generator.strategy(strategyConfig3);
generator.packageInfo(packageConfig);
generator.execute();
}
}
8.配置文件
mybatis-plus:
mapperPackage: com.**.**.mapper
# 对应的 XML 文件位置
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: com.**.**.domain
# 针对 typeAliasesPackage,如果配置了该属性,则仅仅会扫描路径下以该类作为父类的域对象
#typeAliasesSuperType: Class
# 如果配置了该属性,SqlSessionFactoryBean 会把该包下面的类注册为对应的 TypeHandler
#typeHandlersPackage: null
# 如果配置了该属性,会将路径下的枚举类进行注入,让实体类字段能够简单快捷的使用枚举属性
#typeEnumsPackage: null
# 启动时是否检查 MyBatis XML 文件的存在,默认不检查
checkConfigLocation: false
# 通过该属性可指定 MyBatis 的执行器,MyBatis 的执行器总共有三种:
# SIMPLE:该执行器类型不做特殊的事情,为每个语句的执行创建一个新的预处理语句(PreparedStatement)
# REUSE:该执行器类型会复用预处理语句(PreparedStatement)
# BATCH:该执行器类型会批量执行所有的更新语句
executorType: SIMPLE
# 指定外部化 MyBatis Properties 配置,通过该配置可以抽离配置,实现不同环境的配置部署
configurationProperties: null
configuration:
# 自动驼峰命名规则(camel case)映射
# 如果您的数据库命名符合规则无需使用 @TableField 注解指定数据库字段名
mapUnderscoreToCamelCase: true
# 默认枚举处理类,如果配置了该属性,枚举将统一使用指定处理器进行处理
# org.apache.ibatis.type.EnumTypeHandler : 存储枚举的名称
# org.apache.ibatis.type.EnumOrdinalTypeHandler : 存储枚举的索引
# com.baomidou.mybatisplus.extension.handlers.MybatisEnumTypeHandler : 枚举类需要实现IEnum接口或字段标记@EnumValue注解.
defaultEnumTypeHandler: org.apache.ibatis.type.EnumTypeHandler
# 当设置为 true 的时候,懒加载的对象可能被任何懒属性全部加载,否则,每个属性都按需加载。需要和 lazyLoadingEnabled 一起使用。
aggressiveLazyLoading: true
# MyBatis 自动映射策略
# NONE:不启用自动映射
# PARTIAL:只对非嵌套的 resultMap 进行自动映射
# FULL:对所有的 resultMap 都进行自动映射
autoMappingBehavior: PARTIAL
# MyBatis 自动映射时未知列或未知属性处理策
# NONE:不做任何处理 (默认值)
# WARNING:以日志的形式打印相关警告信息
# FAILING:当作映射失败处理,并抛出异常和详细信息
autoMappingUnknownColumnBehavior: NONE
# Mybatis一级缓存,默认为 SESSION
# SESSION session级别缓存,同一个session相同查询语句不会再次查询数据库
# STATEMENT 关闭一级缓存
localCacheScope: SESSION
# 开启Mybatis二级缓存,默认为 true
cacheEnabled: true
global-config:
# 是否打印 Logo banner
banner: true
# 是否初始化 SqlRunner
enableSqlRunner: false
dbConfig:
# 主键类型
# AUTO 数据库ID自增
# NONE 空
# INPUT 用户输入ID
# ASSIGN_ID 全局唯一ID
# ASSIGN_UUID 全局唯一ID UUID
idType: AUTO
# 表名前缀
tablePrefix: null
# 字段 format,例: %s,(对主键无效)
columnFormat: null
# 表名是否使用驼峰转下划线命名,只对表名生效
tableUnderline: true
# 大写命名,对表名和字段名均生效
capitalMode: false
# 全局的entity的逻辑删除字段属性名
logicDeleteField: deleteFlag
# 逻辑已删除值
logicDeleteValue: 1
# 逻辑未删除值
logicNotDeleteValue: 0
# 字段验证策略之 insert,在 insert 的时候的字段验证策略
# IGNORED 忽略判断
# NOT_NULL 非NULL判断
# NOT_EMPTY 非空判断(只对字符串类型字段,其他类型字段依然为非NULL判断)
# DEFAULT 默认的,一般只用于注解里
# NEVER 不加入 SQL
insertStrategy: NOT_EMPTY
# 字段验证策略之 update,在 update 的时候的字段验证策略
updateStrategy: NOT_NULL
# 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件
selectStrategy: NOT_EMPTY
Original: https://www.cnblogs.com/xiaoye-Blog/p/16640630.html
Author: 小也取不到名字
Title: Mybatis-Plus初步上手!!
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/590010/
转载文章受原作者版权保护。转载请注明原作者出处!