文章目录

  • Mybatis-Plus进阶之扩展插件
    • 1、逻辑删除
    • 2、自动填充
    • 3、乐观锁
    • 4、执行sql分析打印
    • 5、多租户实现
    • 6、动态表名解析
    • 7、sql注入器 和 选装件

Mybatis-Plus进阶之扩展插件

MybatisPlus基础篇请看:Mbatis-Plus整合springboot详细学习笔记

基本实体类:

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Employee {// idprivate Long id;// 名称private String name;// 年龄@TableField(fill = FieldFill.UPDATE)private Integer age;// 邮箱private String email;// 上级idprivate Long managerId;/** 设置自动填充 */// 创建时间@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;// 更新时间@TableField(fill = FieldFill.UPDATE)private LocalDateTime updateTime;// 版本号@Versionprivate Integer version;// 逻辑删除的 局部设置@TableField(select = false) // 查询的时候,不显示这个参数@TableLogicprivate Integer deleted;// 子级@TableField(exist = false)private List<Employee> children = new ArrayList<>();}

1、逻辑删除

springboot中配置:

# 配置逻辑删除的值   在这里配置的是  删除的时候为1  未删除的时候为0
mybatis-plus:global-config:db-config:logic-not-delete-value: 0logic-delete-value: 1

需要在实体类的字段上加上逻辑删除的注解:

  // 删除的时候为1  未删除的时候为0@TableLogicprivate Integer deleted;

测试逻辑删除:

// update employee set deleted = 1 where id = ? and deleted = 0
boolean b = employeeService.removeById(1237753494614700033L);// 查询输出后将不会显示刚刚被删除的那条  select * from employee where deleted = 1
List<Employee> list = employeeService.list(null);// 并且只能更新未删除的
int update = employeeMapper.update(null, lambdaUpdateWrapper);

逻辑删除注意事项:

【注意: 自定义的查询方法,系统 不会 自动加上 逻辑删除条件,需要自己手动加上】在mapper中自定义的方法,需要自己手动加上逻辑删除限制条件

2、自动填充

设置自动填充需要在字段上加上注解:

    /** 设置自动填充 */// 创建时间@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;// 更新时间@TableField(fill = FieldFill.UPDATE)private LocalDateTime updateTime;

配置字段自动填充:

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {/***  插入的时候自动填充* @param metaObject*/@Overridepublic void insertFill(MetaObject metaObject) {// fieldName 是实体中的属性名称// 检查是否有这个属性boolean createTime = metaObject.hasSetter("createTime");if (createTime) {this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());}}/*** 修改的时候自动填充* @param metaObject*/@Overridepublic void updateFill(MetaObject metaObject) {/***  先检查时候已经传入值了,若传入值了,则以传入值为准,就不再自动填充       */Object updateTime = getFieldValByName("updateTime", metaObject);// 若没有传入值才自动填充if (updateTime == null) {this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());}}}

测试自动填充以及注意事项:


Employee employee = new Employee();// 此时添加员工数据的时候会自动赋值上创建时间
int rows = employeeMapper.insert(employee);// 这里修改会自动填充修改时间
int rows = employeeMapper.updateById(employee);// 注意这种情况下【不会】自动填充修改时间
int update = employeeMapper.update(null, lambdaUpdateWrapper);// 有实体传入的情况下,会自动填充修改时间
int update = employeeMapper.update(employee, lambdaUpdateWrapper);

3、乐观锁

配置乐观锁插件:

@Slf4j
@Configuration
public class MybatisPlusConfig {/***  乐观锁插件* @return*/@Beanpublic OptimisticLockerInterceptor optimisticLockerInterceptor() {return new OptimisticLockerInterceptor();}
}

实体类中字段上加上乐观锁注解:

    // 版本号@Versionprivate Integer version;

乐观锁测试:

boolean b = employeeService.updateById(employee);
// 第二个参数为,【查询】  重点
boolean update = employeeService.update(employee,lambdaQueryWrapper);

注意事项:

特别说明:

  • 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime

  • 整数类型下 newVersion = oldVersion + 1

  • newVersion 会回写到 entity

  • 仅支持 updateById(entity)update(entity, wrapper) 方法

  • update(entity, wrapper) 方法下, wrapper 不能复用!!!

4、执行sql分析打印

引入依赖:

  <!-- 执行sql 分析打印 依赖--><dependency><groupId>p6spy</groupId><artifactId>p6spy</artifactId><version>3.8.2</version></dependency>

更改数据库配置:

spring:datasource:driver-class-name: com.p6spy.engine.spy.P6SpyDriverurl: jdbc:p6spy:mysql://127.0.0.1:3306/mybatisplus?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8username: rootpassword: root

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# 将日志输出到指定的位置
#logfile=log.log

注意事项:

    driver-class-name 为 p6spy 提供的驱动类url 前缀为 jdbc:p6spy 跟着冒号为对应数据库连接地址打印出sql为null,在excludecategories增加commit批量操作不打印sql,去除excludecategories中的batch批量操作打印重复的问题请使用MybatisPlusLogFactory (3.2.1新增)该插件有性能损耗,不建议生产环境使用

5、多租户实现

需要在分页配置类中配置:


@Slf4j
@Configuration
public class MybatisPlusConfig {/***    分页配置中,设置多租户信息*/@Beanpublic PaginationInterceptor paginationInterceptor() {PaginationInterceptor paginationInterceptor = new PaginationInterceptor();ArrayList<ISqlParser> sqlParsers = new ArrayList<>();// 租户解析器TenantSqlParser tenantSqlParser = new TenantSqlParser();tenantSqlParser.setTenantHandler(new TenantHandler() {@Overridepublic Expression getTenantId(boolean where) {// 租户的id,这里测试固定写死return new LongValue(1088248166370832385L);}// 多租户字段是什么@Overridepublic String getTenantIdColumn() {// 这是表中的字段名,即 用于区分租户的字段return "manager_id";}// 是否需要排除某些表,不加租户字段@Overridepublic boolean doTableFilter(String tableName) {// 为 角色 表的时候,不增加租户信息if("role".equals(tableName)){// 不增加租户信息return true;}return false;}});sqlParsers.add(tenantSqlParser);paginationInterceptor.setSqlParserList(sqlParsers);/【特定sql 过滤】,可用注解替换 @SqlParser(filter = true) 为true表示,不在此方法上增加租户信息/paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() {@Overridepublic boolean doFilter(MetaObject metaObject) {MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);if ("cn.mesmile.mybatisplusdemo.mapper.EmployeeMapper.selectAll".equals(ms.getId())) {// 同时这个方法对 动态表明解析也会产生作用,也会过滤掉动态表名,只显示原来的表名// 不增加租户信息return true;}return false;}});return paginationInterceptor;}
}

过滤得到不使用多租户用户的方法:

@Component
public interface EmployeeMapper extends MyMapper<Employee> {/***  这是自定义的查询方法* @param wrapper*/
//    @SqlParser(filter = true) 该注解为true 设置该方法,不需要要加入租户信息@Select("select * from employee ${ew.customSqlSegment}")List<Employee> selectAll(@Param(Constants.WRAPPER)Wrapper<Employee> wrapper);}

6、动态表名解析

配置动态表名解析器:

@Slf4j
@Configuration
public class MybatisPlusConfig {public static ThreadLocal<String> myTableName = new ThreadLocal<>();/***  mybatis-plus 的分页配置里面配置 动态表名解析器* @return*/@Beanpublic PaginationInterceptor paginationInterceptor() {PaginationInterceptor paginationInterceptor = new PaginationInterceptor();ArrayList<ISqlParser> sqlParsers = new ArrayList<>();// 动态表名解析器DynamicTableNameParser dynamicTableNameParser = new DynamicTableNameParser();HashMap<String, ITableNameHandler> tableNameHandlerHashMap = new HashMap<>();// 第一参数是需要  动态替换的表名tableNameHandlerHashMap.put("employee", new ITableNameHandler() {@Overridepublic String dynamicTableName(MetaObject metaObject, String sql, String tableName) {log.info("metaObject:  {}", metaObject);log.info("原表执行的 sql:  {}", sql);log.info("原表的名称 tableName:  {}", tableName);// 【这里返回动态的表名】// 如果返回的值为空,则不进行替换  这里返回的事 动态表名return myTableName.get();}});dynamicTableNameParser.setTableNameHandlerMap(tableNameHandlerHashMap);sqlParsers.add(dynamicTableNameParser);paginationInterceptor.setSqlParserList(sqlParsers);return paginationInterceptor;}
}

注意:【在多租户配置这里 , 过滤的方法, 动态表名不会生效】

/【特定sql 过滤】,可用注解替换 @SqlParser(filter = true) 为true表示,不在此方法上增加租户信息/paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() {@Overridepublic boolean doFilter(MetaObject metaObject) {MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);if ("cn.mesmile.mybatisplusdemo.mapper.EmployeeMapper.selectAll".equals(ms.getId())) {// 同时这个方法对 动态表明解析也会产生作用,也会过滤掉动态表名,只显示原来的表名// 不增加租户信息return true;}return false;}});

例:

@Component
public interface EmployeeMapper extends BaseMapper<Employee> {/***  这是自定义的查询方法* @param wrapper* @return*///该注解为true 设置该方法,不需要要加入租户信息//@SqlParser(filter = true) @Select("select * from employee ${ew.customSqlSegment}")List<Employee> selectAll(@Param(Constants.WRAPPER)Wrapper<Employee> wrapper);}

测试:


MybatisPlusConfig.myTableName.set("employee_2020");LambdaQueryWrapper<Employee> employeeLambdaQueryWrapper = Wrappers.lambdaQuery();// 当自定义查询方法[有] @SqlParser(filter = true) 时候:select * from employee 动态表名不生效
// 当自定义查询方法[没有] @SqlParser(filter = true) 时候:select * from employee_2020 动态表名生效
List<Employee> employees = employeeMapper.selectAll(employeeLambdaQueryWrapper);

7、sql注入器 和 选装件

public class DeleteAllMethod extends AbstractMethod {@Overridepublic MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {// 执行的sqlString sql = "delete from "+ tableInfo.getTableName();// mapper 接口方法名String method = "deleteAll";SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);return addDeleteMappedStatement(mapperClass, method , sqlSource);}
}
@Component
public class MySqlInjector extends DefaultSqlInjector {@Overridepublic List<AbstractMethod> getMethodList(Class<?> mapperClass) {// 获取到父类已有的抽象方法List<AbstractMethod> methodList = super.getMethodList(mapperClass);// 将自定义的类方法 加入到父类的集合中methodList.add(new DeleteAllMethod());return methodList;}
}

在mapper类中写入方法:


@Component
public interface EmployeeMapper extends BaseMapper<Employee> {/***  自定义的sql注入方法,删除所有* @return 返回受影响行数*/int deleteAll();
}

选装件:InsertBatchSomeColumn 、 LogicDeleteByIdWithFill 、AlwaysUpdateSomeColumnById

加入选装件:

@Component
public class MySqlInjector extends DefaultSqlInjector {@Overridepublic List<AbstractMethod> getMethodList(Class<?> mapperClass) {List<AbstractMethod> methodList = super.getMethodList(mapperClass);// 将自定义的类方法 加入到父类的集合中methodList.add(new DeleteAllMethod());// 【选装件】 插入的时候,不插入【逻辑删除】 和 【age年龄】methodList.add(new InsertBatchSomeColumn(t -> !t.isLogicDelete() && !t.getColumn().equals("age")));// 【选装件】 逻辑删除的时候同时再修改值,但是修改值得字段上要加上注解 @TableField(fill = FieldFill.UPDATE)methodList.add(new LogicDeleteByIdWithFill());// 【选装件】 根据id更新固定的几个字段(但是不包括逻辑删除)  这里 不更新 name 字段methodList.add(new AlwaysUpdateSomeColumnById(t -> !t.getColumn().equals("name")));return methodList;}
}

在mapper接口中写选装件方法:

public interface MyMapper<T> extends BaseMapper<T> {/***  自定义的sql注入方法,删除所有* @return 返回受影响行数*/int deleteAll();/***  mybatis-plus 中的【选装件】 , 自定义批量插入* @param list* @return*/int insertBatchSomeColumn(List<T> list);/*** mybatis-plus 中的额【选装件】 , 自定义删除**  在删除的同时,填充值修改值,需要在 修改的字段上 加注解*          @TableField(fill = FieldFill.UPDATE)*          private Integer age;* @param entity* @return*/int deleteByIdWithFill(T entity);/***  mybatis-plus 中的额【选装件】*      指定更新某些字段* @param entity* @return*/int alwaysUpdateSomeColumnById(@Param(Constants.ENTITY) T entity);
}

Mybatis-Plus进阶之扩展插件相关推荐

  1. Mybatis分库分表扩展插件

    参考:http://fangjialong.iteye.com/blog/2240880

  2. springboot进阶,分页插件 pageHelper,Swagger整合,日志

    文章目录 1,课程回顾 2,本章重点 3,具体内容 3.1 整合连接池 3.2 springboot日志配置: 3.3 springboot整合shiro 3.4 mybatis分页插件 pageHe ...

  3. VS Code 安装插件、自定义模板、自定义配置参数、自定义主题、配置参数说明、常用的扩展插件

    1. 下载和官网教程 下载地址:https://code.visualstudio.com/ 官方教程:https://code.visualstudio.com/docs 2. 安装插件 安装扩展插 ...

  4. jupyter扩展插件Nbextensions的安装、使用

    jupyter扩展插件Nbextensions的安装.使用 # 使用pypi里面包进行安装 pip install jupyter_contrib_nbextensions # 也可以通过如下方式进行 ...

  5. javascript扩展插件alook_使用 Kotlin 编写你的第一个 Firefox WebExtension 扩展

    Kotlin 是我最喜爱的编程语言.我们已经知道 Kotlin 编译成 Java 字节码可以快速被安卓和服务端采用.事实上,Kotlin 还支持编译成 JavaScript,因此该语言也开始在 Web ...

  6. vscode 结束_8 个给前端的顶级 VS Code 扩展插件

    翻译:京程一灯 原文:https://1stwebdesigner.com/top-free-extensions-for-vs-code/ 微软的 VS (Visual Studio) Code 是 ...

  7. 【Visual Studio 2019】上传代码到 GitHub ( 16.9.2 版本 | 安装 GitHub 扩展插件 | 创建 Git 仓库 | 推送到远程仓库 )

    文章目录 一.安装 GitHub 扩展插件 二.创建 Git 仓库 三.推送到远程仓库 今天将 Visual Studio 2019 从 16.3.6 版本升级到了 16.9.2 版本 , 发现相关操 ...

  8. java代码里的JSON格式怎么写好看_谁会不爱让代码骚里骚气的VSCode扩展插件呢?...

    点击上方 "Python人工智能技术" 关注,星标或者置顶22点24分准时推送,第一时间送达 来自:公众号 读芯术 | 编辑:真经君 码农真经(ID:coder_experienc ...

  9. reactjs redux chrome扩展插件

    reactjs redux chrome扩展插件 React Developer ToolsRedux DevTools

最新文章

  1. 【全网之最】用JavaScript写一个最简短的语句实现从A数组中去除B数组中相同元素
  2. 导出Windows服务器下的Oracle数据库并导入到Linux服务器下的Oracle数据库中
  3. 中小学计算机教室设备维修记录,多媒体电教室的管理与设备的维护
  4. 完全备份指的是对整个计算机系统,网络安全管理实践题库:在备份技术中,差分备份就是对整个系统所有文件进行完全备份,包括所有系统和数据。()...
  5. WebLogic8.1 配置SSL/HTTPS单向认证
  6. aspen共沸精馏如何模拟_9月1011号Aspen plus:精馏精品培训!线上线下同时开展!另有惊喜活动等你参与!...
  7. 设置图片圆角 或者圆形
  8. [vue] 第一次加载页面时会触发哪几个钩子?
  9. WEB服务器技术名词
  10. Linaro GCC 交叉编译工具链 国内源下载列表 (持续更新)
  11. 【版本更新】CAD组件Aspose.CAD 9月新版V17.9发布 | 支持IFC格式
  12. dicom格式怎么转换_qsv怎么转换mp4格式?qsv转mp4的首选工具
  13. matlab 读取同一文件中所有图像_matlab 批量读取文件夹内所有图片的几种方法
  14. 高等数学18讲(19版)反常积分的计算与敛散性判别
  15. SVN教程代码比较(图文教程)
  16. 模电学习1. 三极管基础知识及常用电路
  17. 自己写的txt分割器
  18. 高含盐废水处理资源化——双极膜电渗析
  19. 做自己喜欢的事情,是假的,改变世界也是假的
  20. Clion 调教记录

热门文章

  1. K8s中的CNI网络模型
  2. 数据分析---pandas(一)
  3. 002 Ubuntu系统设置之调整界面大小
  4. word2003下的神秘咒语——灵活的棕色狐狸跳过懒狗
  5. Movement Disorders脑电格兰杰因果分析:运动皮质在帕金森病复发性震颤中的作用
  6. 《UNIX网络编程》配置unp.h头文件
  7. LED照明各国认证及标准发展趋势
  8. 解决Hyperledger Fabric通道重复创建问题( readset expected key [Group] /Channel/Application at version 0, but )
  9. 关于对接芝麻 GO 的几点问题
  10. MVC中的URL路由(一)