MybatisPlus实战笔记

news/2024/5/20 22:12:25/文章来源:https://blog.csdn.net/lonelymanontheway/article/details/105981404

概述

Mybatis支持定制化SQL、存储过程以及高级映射,避免几乎所有的 JDBC 代码和手动设置参数以及获取结果集。可以使用简单的 XML 或注解来配置和映射原生信息,将接口和Java的POJO映射成数据库中的记录。

缺点:
SQL工作量很大,尤其是字段较多时。单表的增删改查操作可以通过mybatis generator工具来生成(或自己写模板工具生成),但项目开发的过程中总免不了要新添加新字段,得把新字段写到原来的所有增删改查的sql中。
mybatis的单表操作比较麻烦,因为筛选的条件可能会各种各样,所以不得不写很多动态sql来兼容查询条件。

MybatisPlus(简称MP)的出现,可以一定程度上优化上述问题,MP集Mybatis与Hibernate的优点。提供Hibernate的单表CRUD操作的方便同时,又保留Mybatis的特性。在Mybatis的基础上只做增强不做改变,为简化开发、提高效率而生。

特点:

  • 无侵入:只做增强不做改变
  • 损耗小:启动即自动注入基本CRUD,直接面向对象操作
  • 强大的CRUD操作:内置通用Mapper、Service,通过少量配置即可实现单表大部分CRUD操作,还有条件构造器
  • 支持多种数据库:
  • 支持Lambda形式调用:
  • 支持主键自动生成:4中主键策略(包括分布式唯一ID生成器-Sequence),可以自由配置,解决主键问题
  • 支持XML热加载:mapper.xml支持热加载,简单的CRUD操作无需重启,甚至支持无XML启动
  • 支持ActiveRecord模式
  • 内置代码生成器:
  • 支持关键词自动转义:
  • 支持自定义全局通用操作:
  • 解除SQL与程序代码的耦合
  • 提供映射标签
  • 提高对象关系映射标签
  • 通过xml标签,支持编写动态SQL

具体的:
在这里插入图片描述

架构

架构原理,可参考

功能

注解

@TableId, 用于主键,MP 支持4种主键策略 IdType
@TableName,用于表名
@TableField,字段,exist=true/false,是否对应数据表字段
@Version,乐观锁标记
@KeySequence,序列主键策略,主要
@TableLogic,用于逻辑删除的字段

全局配置 GlobalConfiguration

需要注入到MybatisSqlSessionFactoryBean里面,才能生效
dbColumnUnderline,MP2.3默认为true
idType配置后无需对所有的主键加注解
tablePrefix,仅适用于所有表名前缀相同的情况下

直接获取主键值,无需任何配置,基于BaseMapper

Mapper,顶级Mapper,继承该接口后,无需编写mapper.xml文件,即可获得CRUD功能,支持 id 泛型

insertAllColumn(); // 无需对全部字段进行setter,然后反应到DB层,落值为null
insert(); 			// 对全部字段有非空判断
updateById();
updateAllColumnById(); // 没有setter时会覆盖原有数据为null
T selectById(Serializable id);
T selectOne(@Param("ew") T entity);
List<T> selectBatchIds(List<? extends Serializable> idList);
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
List<T> selectPage(RowBounds rowBounds, @Param("ew") Wrapper<T> wrapper);

RowBounds,分页查询条件,SQL语句没有limit关键字,不是真实的物理分页?!
Page,分页辅助类,

分页插件

Spring Boot配置方式:

@Bean
public PaginationInterceptor paginationInterceptor() {return new PaginationInterceptor();
}

UserMapper.java:

List<User> getList(Pagination page, Integer status);

UserServiceImpl.java调用分页方法,需要page.setRecords回传给页面:

public Page<User> getList(Page<User> page, Integer status) {return page.setRecords(userMapper.getList(page, status));
}

Mybatis PageHelper对比MP PaginationInterceptor

Mybatis PageHelper是独立于Mybatis的依赖包,需要引入多个maven依赖。而MP PaginationInterceptor是MP自带插件,是否启用插件取决于是否配置。底层原理都是使用拦截器实现。

公共字段自动填充

平时在建对象表时都会有最后修改时间last_update_time,最后修改人last_update_name这两个字段,对于这些大部分表都有的字段,每次在新增和修改的时候都要考虑到这几个字段有没有传进去,很麻烦。

MybatisPlus公共字段自动填充的功能可以解决此问题。一般满足下面条件的字段就可以使用此功能:

  • 这个字段是大部分表都会有的。
  • 这个字段的值是固定的,或则字段值是可以在后台动态获取的。

MybatisPlus 2.0.6版本支持更新数据公共字段自动填充,之前都是只支持新增数据的时候可以使用。

配置:
继承IMetaObjectHandler抽象类,实现两个方法,insertFill()用于新增数据时需要填充的字段,updateFill()用于更新数据时需要填充的字段:

import org.apache.ibatis.reflection.MetaObject;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Component;
import com.baomidou.mybatisplus.mapper.MetaObjectHandler;
/** mybatisplus自定义填充公共字段, 即没有传的字段自动填充*/
@Component
public class MyMetaObjectHandler extends MetaObjectHandler  {// 新增填充@Overridepublic void insertFill(MetaObject metaObject) {Object lastUpdateNameId = metaObject.getValue("lastUpdateNameId");Object lastUpdateTime = metaObject.getValue("lastUpdateTime");// 获取当前登录用户SysUser user = (SysUser)SecurityUtils.getSubject().getPrincipal();if (null == lastUpdateNameId) {metaObject.setValue("lastUpdateNameId", user.getId());}if (null == lastUpdateTime) {metaObject.setValue("lastUpdateTime", new Date());}}// 更新填充@Overridepublic void updateFill(MetaObject metaObject) {insertFill(metaObject);}
}

getValue()方法的参数是POJO类里面的变量(驼峰的命名方式)。
在MybatisPlus的配置文件中公共字段生成类的bean:

// 全局配置
GlobalConfiguration globalConfig = new GlobalConfiguration();
// 配置公共字段自动填写
globalConfig.setMetaObjectHandler(new MyMetaObjectHandler());

也就是将刚刚写的公共字段填充的设置设置到MP全局配置的对象中。
填充的字段需要忽略验证,在表对象pojo类的对应属性上添加下面注解:

@TableField(value = "last_update_id", validate = FieldStrategy.NOT_EMPTY)
private String lastUpdateNameId;
@TableField(value = "last_update_time", validate = FieldStrategy.NOT_EMPTY)
private Date lastUpdateTime;

原因:因为调用更新和插入的方法时,会验证你所传的属性是否为空,来判断是否该更新和插入这个属性,这个就和公共字段自动填充相冲突,所以需要这个注解来标识此属性不需要验证。不然在插入的时候就会填充失败。

测试

// 公共字段自动填充
// 1.在mybatisplus的配置文件中公共字段生成类的bean
// 2.实现IMetaObjectHandler类
// 3.忽略对应字段的为空检测,在pojo类的属性上添加@TableField(value="last_update_name_id",validate=FieldStrategy.IGNORED)
@Test
public void publicTest(){SysUser user = new SysUser();sysUserService.insert(user);sysUserService.selectById(user.getId());SysUser user1 = new SysUser();user1.setId(user.getId());sysUserService.updateById(user1);sysUserService.selectById(user.getId());
}

本来是打算创建人和创建时间,也使用这种方法处理的,最后发现,如果将这两个字段也忽略为空的判断,也就是加上validate=FieldStrategy.NOT_EMPTY,在更新数据的时候会将创建人和创建时间一起更新,不传的话就会更新为空。但是在正真用的上的需求上面使用的时候还不够完善。

逻辑删除

使用此插件后的效果:

  1. 在mp自带查询和更新方法的SQL后面,追加<逻辑删除字段>=<LogicNotDeleteValue默认值>
  2. 删除方法: deleteById()和其他delete方法,底层SQL为:update tbl_xxx set <逻辑删除字段>=<logicDeleteValue默认值>

配置如下:

  1. 修改集成全局注入器为 LogicSqlInjector
  2. application.yml全局注入值:logicDeleteValue // 逻辑删除全局值 logicNotDeleteValue // 逻辑未删除全局值

自定义注入器的一种,
需要@TableLogic
问题:不能配置多个AutoSqlInjector注入器?
在这里插入图片描述

支持XML热加载

在使用MyBatis本地开发时,需要经常性地修改调整mapper.xml文件。IDEA虽然自带热更新(热加载)功能,但是对于mapper.xml文件却不奏效,也就是说在修改mapper.xml文件后,需要重启应用。

哪怕应用足够轻量级或者优化得足够好,启动也需要好几秒时间。此时有个mapper.xml文件热加载功能就可以提高开发效率。

经过调研,是可以实现的,参考:MyBatis系列之mapper.xml实现热加载HotSwap。

而MP自带mapper.xml文件热加载功能。

模糊查询

like
notlike
likeLeft
likeRight

代码生成

在这里插入图片描述

配置好generator.properties文件:

# 包前缀
package=com.github
# 模块名
moduleName=shop
# 作者名
author=johnny
email=
# 表前缀,如表tb_sys_user 生成类 sys_user
tablePrefix=m_,r_,s_
# 数据转换类型
tinyint=Boolean
smallint=Integer
mediumint=Integer
int=Integer
integer=Integer
bigint=Long
float=Float
double=Double
decimal=BigDecimal
bit=Boolean
char=String
varchar=String
tinytext=String
text=String
blob=String
mediumtext=String
longtext=String
date=Date
datetime=Date
timestamp=Date

定义好velocity模板文件(pom文件需要引入velocity依赖),从数据表PO实体类到Controller接口方法都支持自动生成:Model.java.vmMapper.java.vmMapper.xml.vmService.java.vmServiceImpl.java.vmController.java.vm

如:

package ${package}.${moduleName}.model;import ${package}.common.model.SuperEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
#if(${hasBigDecimal})
import java.math.BigDecimal;
#end
import java.util.Date;/*** ${comments}** @author ${author}*/
@Data
@TableName("${tableName}")
public class ${className} extends SuperEntity {#foreach ($column in $columns)#if($column.columnName != $pk.columnName && $column.columnName != "createTime" && $column.columnName !="updateTime")private $column.attrType $column.attrname;#end
#end
}

其他

执行分析,性能分析,乐观锁,XML热加载,自定义全局操作,逻辑删除,读写分离&多数据源,主键Sequence,多租户SQL解析器,通用枚举自动注入,IDEA快速开发;

条件构造器

EntityWrapper/Condition,都是基于Wrapper,Wrapper抽象类的方法:
在这里插入图片描述

.last()有SQL注入的风险

AR

Active Record,一种数据访问设计模式,它可以帮助你实现数据对象Object到关系数据库的映射。
Model,实现pkVal抽象方法,指定当前实体类的主键属性
EntityWrapper,支持泛型,builder模式,

不用注入aaaMapper,

AutoGenerator


Oracle 主键问题

使用@KeySequence解决,用在实体类上,
数据库层面:

create sequence seq_user start with 100 increment by 2;
-- 查询序列的下一个值
select seq_user.nextval from dual;
-- 查询序列的当前值
select seq_user.currval from dual;

2.问题
mybatis-plus怎么实现单表URUD操作?
mybatis-plus的底层实现原理是什么?
mybatis-plus与其他同类框架如mybatis helper有很什么优势?
如何集成mybatis-plus快速搭建一个spring boot项目。

参考

MyBatis-Plus源码分析

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_340014.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

5款无广告的超实用软件,建议收藏!

​ 大家好,我又来了,今天向大家推荐几款软件,它们有个共同的特点,就是无广告、超级实用,大家看完之后,可以自己去搜索下载试用。 1.重复文件清理——Duplicate Cleaner ​ Duplicate Cleaner是一款用于找出硬盘中重复文件并删除的工具。它可以通过内容或文件名查找重复文档、…

Delphi Professional Crack,IDE插件开发和扩展IDE

Delphi Professional Crack,IDE插件开发和扩展IDE 构建具有强大视觉设计功能的单源多平台本机应用程序。 Delphi帮助您使用Object Pascal为Windows、Mac、Mobile、IoT和Linux构建和更新数据丰富、超连接、可视化的应用程序。Delphi Professional适合个人开发人员和小型团队构建…

Qt 6. 其他类调用Ui中的控件

1. 把主类指针this传给其他类&#xff0c;tcpClientSocket new TcpClient(this); //ex2.cpp #include "ex2.h" #include "ui_ex2.h"Ex2::Ex2(QWidget *parent): QDialog(parent), ui(new Ui::Ex2) {ui->setupUi(this);tcpClientSocket new TcpClient…

有利于提高xenomai /PREEMPT-RT 实时性的一些配置建议

版权声明:转自: https://www.cnblogs.com/wsg1100 一、前言 1. 什么是实时 “实时”一词在许多应用领域中使用,人们它有不同的解释,并不总是正确的。人们常说,如果控制系统能够对外部事件做出快速反应,那么它就是实时运行的。根据这种解释,如果系统速度快,则系统被认…

数据结构入门指南:带头双向循环链表

目录 文章目录 前言 1.结构与优势 2.链表实现 2.1 定义链表 2.2 创建头节点 2.3 尾插 2.4 输出链表 2.5 尾删 2.6 头插 2.7头删 2.8 节点个数 2.9 查找 2.10 位置插入 2.11 位置删除 2.12 销毁链表 3. 源码 总结 前言 链表一共有8种结构&#xff0c;但最常用的就是无头单…

IDEA的实用快捷键大全

目录 1.常规快捷键 1.1通用类 1.2注释类 1.3操作类 1.4展开与关闭 2.智能补全类快捷键 3.程序结构类快捷键 4.统一操作快捷键 1.常规快捷键 1.1通用类 像 Ctrl C 复制&#xff0c; Ctrl V 粘贴&#xff0c; Ctrl S保存文件&#xff0c; Ctrl X剪切&#xff0c;这种…

【深度学习】SMILEtrack: SiMIlarity LEarning for Multiple Object Tracking,论文

论文&#xff1a;https://arxiv.org/abs/2211.08824 代码&#xff1a;https://github.com/WWangYuHsiang/SMILEtrack 文章目录 AbstractIntroductionRelated WorkTracking-by-DetectionDetection methodData association method Tracking-by-Attention Methodology架构概述外观…

Excel功能总结

1&#xff09;每一张表格上都打印表头 “页面布局”-->“打印标题”-->页面设置“工作表”页-->打印标题“顶端标题行” 如&#xff1a;固定第1~2行&#xff0c;设置成“$1:$2” 2&#xff09;将页面内容打印在一页【缩印】 1.选好需要打印的区域&#xff0c;“页面布…

“单片机定时器:灵活计时与创新功能的关键“

学会定时器的使用对单片机来说非常重要&#xff0c;因为它可以帮助实现各种时序电路。时序电路在工业和家用电器的控制中有广泛的应用。 举个例子&#xff0c;我们可以利用单片机实现一个具有按钮控制的楼道灯开关。当按钮按下一次后&#xff0c;灯会亮起并持续3分钟&#xff…

删除这4个文件夹,流畅使用手机无忧

在现代社会中&#xff0c;手机已经成为我们生活中不可或缺的一部分。然而&#xff0c;随着使用时间的增长&#xff0c;我们可能会遇到手机卡顿和内存不足的问题&#xff0c;让我们感到十分困扰。手机卡顿不仅影响使用体验&#xff0c;还可能导致应用程序运行缓慢&#xff0c;甚…

网络安全 Day26-PHP 简单学习

PHP 简单学习 1. 为什么要学习PHP2. PHP语法3. php 变量4. 字符串数据5. PHP 函数6. 数组 1. 为什么要学习PHP php存量多开源软件多很多安全流程 渗透方法 sql注入基于PHP语言入门简单 2. PHP语法 格式: <?php 内容?>或<?内容?>结尾分号例子<?php phpin…

网络安全(秋招)如何拿到offer?(含面试题)

以下为网络安全各个方向涉及的面试题&#xff0c;星数越多代表问题出现的几率越大&#xff0c;祝各位都能找到满意的工作。 注&#xff1a;本套面试题&#xff0c;已整理成pdf文档&#xff0c;但内容还在持续更新中&#xff0c;因为无论如何都不可能覆盖所有的面试问题&#xf…

Python小白学习:超级详细的字典介绍(字典的定义、存储、修改、遍历元素和嵌套)

目录 一、字典简介1.1 创建字典1.2 访问字典中的值1.3 添加键值对1.4 修改字典中的值实例 1.5 删除键值对1.6 由多个类似对象组成的字典1.7 使用get()访问值1.8 练习题 二、遍历字典2.1 遍历所有键值对实例 2.2 遍历字典中的所有键2.3 按照特定顺序遍历字典中的所有键2.4 遍历字…

在java中存储对象到redis出现类型转换异常的解决方法

**出现的问题,**此时的redisCatch已经注入 原因:这里传进来的是一个对象,redis不能直接将对象存到String中,必须将对象进行序列化转成json字符串再存储,其次.传进来的对象不能是null 再重新启动就行了

Java阶段五Day21

Java阶段五Day21 文章目录 Java阶段五Day21问题解析rocketmq清空数据 linux学习背景什么是linux系统虚拟机介绍启动 虚拟机linux虚拟机网络的问题 linux系统的基础命令命令提示符命令格式pwd指令ls指令cd指令mkdirtouch指令cp指令rm指令mv指令cat指令tail指令 文本编辑器vim操作…

k8s存储卷

目录 一、为什么要存储卷&#xff1f;二、emptyDir存储卷三、hostPath存储卷四、 nfs共享存储卷五、PVC 和 PV5.1 PV和PVC之间的相互作用遵循的生命周期5.2 PV 的状态5.3 一个PV从创建到销毁的具体流程 六、静态创建pv和pvc资源由pod运用过程6.1 在NFS主机上创建共享目录&#…

Hopfield神经网络求解旅行商(TSP)问题matlab代码

1案例背景 1.1连续Hopfield神经网络概述 1.网络结构 连续Hopfield神经网络(Continuous Hopfield Neural Network,CHNN)的拓扑结构和离散Hopfield神经网络的结构类似,如图11-1所示。连续Hopfield网络和离散Hopfield 网络的不同点在于其传递函数不是阶跃函数,而是连续函…

《皮囊》阅读笔记

《皮囊》阅读笔记 2023年8月2号在杭州小屋读完&#xff0c;该书共收录14篇散文&#xff0c;内容大致分为两部分&#xff1a;前半部分讲述作者的阿太&#xff08;外婆的母亲&#xff09;、母亲、父亲关于生活哲学、房子、疾病与信仰的故事&#xff0c;后半部分讲述生活在小镇的张…

SpringBoot Plus+代码生产器

0目录 1. Mybatis Plus 2.代码生产器 1.Mybatis Plus 创建数据库和表&#xff08;id没有设置主键和自增长&#xff09; 创建springBoot导入依赖 安装lombok 配置yml 实体类加入注解 无参构造和有参构造 Mapper接口 扫描接口 测试 加入日志 添加 数据库…

JVM问题

1. jvm运行时区域划分及每个区域的作用 堆、方法区&#xff08;元空间&#xff09;、虚拟机栈、本地方法栈、程序计数器 2. 堆内存分配策略&#xff1a;新生代&#xff0c;老年代&#xff0c;gc时机 • 对象优先分配在Eden区&#xff0c;如果Eden区没有足够的空间进行分配时&am…