当前位置: 首页 > news >正文

mybatis-plus易忘点笔记

mybatis-plus易忘点笔记

安装

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- jdk8, 分页插件分离到这个依赖了 -->
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-jsqlparser-4.9</artifactId>
</dependency><dependencyManagement><dependencies><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-bom</artifactId><version>3.5.15</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>

新版本分页插件挪到mybatis-plus-jsqlparser依赖中了,并且这个依赖分成两个名称,因为jsqlparser 5.0不再支持jdk8了。

可参考官方文档-安装章节

分页

首先需要注册分页插件

@Configuration(proxyBeanMethods = false)
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();paginationInnerInterceptor.setDbType(DbType.MYSQL);interceptor.addInnerInterceptor(paginationInnerInterceptor);return interceptor;}@Beanpublic MetaObjectHandler metaObjectHandler() {return new FillMetaObjectHandler();}
}

分页方法定义

方法的第一个参数必须是IPage对象

自定义方法

IPage<User> list(IPage<User> page, User condition);

BaseMapper内置方法

default <P extends IPage<T>> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper) {page.setRecords(selectList(page, queryWrapper));return page;
}

无论是内置方法还是自定义方法

如果返回类型是 IPage,则入参的 IPage 不能为 null,因为实际返回的IPage对象就是传入的参数IPage对象,会自动调用setRecords方法设置结果

如果返回类型是 List,则需要手动设置入参的 IPage.setRecords(返回的 List)。

临时不分页方案

  • 若返回类型是List,则入参IPage对象传null即可。分页插件会判断如果为空则不拦截。

  • 通用方案,初始化IPage对象时size参数传负数即可。

    IPage<User> page = Page.of(1, -1);
    

只查数据不查count(但是需要分页)

将searchCount属性设置为false

IPage<User> page = Page.of(1, 10, false);

指定count方法

若不想要分页插件自动生成count方法,则指定Page对象的countId属性即可,countId可以不带名称空间,分页插件自己会拼接当前查询方法的名称空间。

适合复杂sql优化场景

自动填充字段

public class FillMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {/** 字段名称、类型需要和实体中的字段名称、类型相匹配* 实体中对应字段存在@TableField(fill = FieldFill.INSERT)或@TableField(fill = FieldFill.INSERT_UPDATE)* 若实体中对应字段本身有值, 则不会去覆盖它* 使用lambda表达式可以避免填充值提前创建*/this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);this.strictInsertFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);}@Overridepublic void updateFill(MetaObject metaObject) {/** 字段名称、类型需要和实体中的字段名称、类型相匹配* 实体中对应字段存在@TableField(fill = FieldFill.UPDATE)或@TableField(fill = FieldFill.INSERT_UPDATE)* 若实体中对应字段本身有值, 则不会去覆盖它* 使用lambda表达式可以避免填充值提前创建*/this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);}
}

实体

/*** 创建时间* updateStrategy = FieldStrategy.NEVER: 更新方法会忽略createTime*/
@TableField(fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NEVER)
private LocalDateTime createTime;/*** 修改时间*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;

FillMetaObjectHandler需要注入到Spring容器中,可以通过 @Component@Bean 注解来实现。

注意事项

  • 如果实体中属性本身有值不会被覆盖,如果填充值为 null 也不会去调用set方法进行填充赋值。
  • 字段必须声明 @TableField 注解,并设置 fill 属性来选择填充策略。
  • update(T entity, Wrapper<T> updateWrapper) 时,entity 不能为空,否则自动填充失效。
  • update(Wrapper<T> updateWrapper) 时不会自动填充,需要手动赋值字段条件。
  • delete操作在符合逻辑删除时(变成了update)也会自动填充。

  • 对于自定义方法,多参数时参数名必须是et

     ```java
    

// 单参数
@Update("update user set age = #{age}, update_time = #{updateTime} where id = #{id}")
int updateAgeById(User user);

/*

  • 单参数带@Param注解或者多参数,参数名称为et的才会被填充
  • 因为带@Param,底层真实的参数对象变成了map,需要一个标记来确定到底要填充map中的哪一个参数
    */
    @Update("update user set age = #{et.age}, update_time = #{et.updateTime} where id = #{et.id}")
    int updateAgeByIdWithParamName(@Param(Constants.ENTITY) User user);
    ```

逻辑删除

全局配置

mybatis-plus:global-config:db-config:logicDeleteField: delFlglogic-delete-value: 1logic-not-delete-value: 0

全局配置时必须实体类中有这个字段才会生效,没有则无效。

实体局部配置

@TableLogic(value = "0", delval = "1")
private Integer delFlg;

简要工作原理

  • 插入:逻辑删除字段的值不受限制。
  • 查找:自动添加条件,过滤掉标记为已删除的记录。
  • 更新:防止更新已删除的记录。
  • 删除:将删除操作转换为更新操作,标记记录为已删除。

例如:

  • 删除update user set deleted=1 where id = 1 and del_flg = 0
  • 查找select id,name,deleted from user where del_flg = 0
  • 修改: update user set name = 'xx' where del_flg = 0

对于插入

  • 方法一:在数据库中为逻辑删除字段设置默认值。
  • 方法二:在插入数据前手动设置逻辑删除字段的值。
  • 方法三:使用 MyBatis-Plus 的自动填充功能。

注意:逻辑删除对自定义Mapper方法无效。

insert或者update方法默认拼接字段规则

当实体中字段值不为null时,就会包含在sql中。

可通过@TableField注解的insertStrategy以及updateStrategy指定。默认值为DEFAULT,因为全局配置的默认值也是DEFAULT,所以效果等同于NOT_NULL

public enum FieldStrategy {/*** 任何时候都加入 SQL*/ALWAYS,/*** 非NULL判断*/NOT_NULL,/*** 非空判断(只对字符串类型字段,其他类型字段依然为非NULL判断)*/NOT_EMPTY,/*** 默认的,一般只用于注解里* <p>1. 在全局里代表 NOT_NULL</p>* <p>2. 在注解里代表 跟随全局</p>*/DEFAULT,/*** 不加入 SQL*/NEVER
}

因此如果想要修改字段值为null,最好使用wrapper

/** UPDATE user SET age=null WHERE del_flg=0 AND (id = 28)*/
ChainWrappers.lambdaUpdateChain(userMapper).set(User::getAge, null).eq(User::getId, 28).update();

批量新增修改方法

default List<BatchResult> insert(Collection<T> entityList) {return insert(entityList, Constants.DEFAULT_BATCH_SIZE);
}default List<BatchResult> updateById(Collection<T> entityList) {return updateById(entityList, Constants.DEFAULT_BATCH_SIZE);
}

可以和别的方法在一个事务中共存,批量方法是新开了一个ExecutorType=BATCH的DefaultSqlSession,注意不能是SqlSessionTemplate,如果是SqlSessionTemplate,底层执行时会去拿绑定在ThreadLocal中的DefaultSqlSession,其中会校验ExecutorType,不能进行修改。而新开一个DefaultSqlSession,由于Mybatis中的Transaction对象为SpringManagedTransaction,因此底层的Connection是共享的,由Spring事务管理器绑定在ThreadLocal中,因此能共享同一个事物,且这个新开的DefaultSqlSession调用commit时是没有任何效果的,由Spring事务管理器统一提交和回滚事务。

http://www.jsqmd.com/news/798691/

相关文章:

  • 《凰标》与《第一大道》:同一宇宙下的龙凤双璧@凤凰标志
  • 2026 苏州 GEO 服务商五强横评 产业适配选型与避坑全指南 - GEO优化
  • 需求实现-ddd四层架构实现
  • 2026 上海 GEO 服务商五强评测 全场景选型指南与避坑实战手册 - GEO优化
  • AI时代数据中心架构变革:从计算中心到加速基础设施
  • 鸿蒙 App 的 Task + State 双核心架构
  • 加州自动驾驶测试报告解读:数据背后的技术演进与行业趋势
  • 线阵相机
  • 5 亿!Vbot 完成 Pre - A 轮融资,加速机器狗交付与人形机器人研发
  • 告别Wireshark手动分析:用Python的flowcontainer库5分钟搞定pcap流量特征提取
  • 2026 重庆 GEO 服务商选型全攻略 五强实力横评与新手避坑指南 - GEO优化
  • 2026年五大B2B整合推广公司深度盘点与品牌选型推荐指南 - GEO优化
  • STM32——OLED显示图片
  • 用Yii2快速构建微服务RESTful API全攻略
  • 41《CAN总线报文周期、抖动与实时性分析》
  • 后端开发必看:设计高并发系统时,如何估算你的RTT和时延带宽积?
  • 别再死记硬背公式了!用Python代码实战理解无人机姿态的三种表示法(欧拉角、DCM、四元数)
  • 实时交通+天气+限行政策+司机疲劳度四维融合——Gemini重构Google Maps路线决策逻辑(仅限首批200家ISV开放调用)
  • 5分钟搞定专业神经网络图:Draw.io开源模板库终极指南
  • 如何自定义查询历史记录面板的展示风格_时间轴样式设计
  • 2026年谷歌广告投放机构怎么选?5家头部平台多维横向实测解析 - GEO优化
  • Pearcleaner:macOS系统清理的终极免费工具,彻底告别应用残留问题
  • OpenSCENARIO实战:从标准到场景的构建指南
  • 低精度SIMD脉冲神经网络引擎L-SPINE设计与优化
  • S7-1200 Modbus TCP 通信客户端指令块 MB_CLIENT
  • 避坑指南:CPAL脚本中diagGetRespPrimitiveByte提取诊断响应数据的正确姿势
  • 专业媒体数字化转型:从EE Times改版看响应式设计与内容生态构建
  • AMD收购赛灵思:异构计算时代下的战略整合与行业格局重塑
  • Honey Select 2终极优化指南:HS2-HF Patch完整解决方案
  • 阿里巴巴Qwen模型深度整合淘宝:对话式购物取代搜索,优化移动端购物体验