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

让mybatis-plus支持null字段全量更新

文章目录

      • 背景
      • 方案一
      • 使用
      • 方案二
      • 方案二原理介绍

背景

如果仅仅只是标题所列的目标,那么mybatis-plus 中可以通过设置
mybatis-plus.global-config.db-config.field-strategy=ignored
来忽略null判断,达到实体字段为null时也可以更新数据为null
但是一旦使用了这个策略,就相当于所有业务代码都会按照这个策略执行。
但是我们的业务往往需要如下支持
1、支持null字段全部更新
2、支持非null更新
3、支持指定null字段更新
所以单独设置某一个策略是很难满足实际的业务场景,因此我们需要在写具体业务代码的时候能够根据需要选择合适的方式。

mybatis-plus字段的四种策略

  • default 默认的,一般只用于注解里
    • 在全局里代表 NOT_NULL
    • 在注解里代表 跟随全局
  • ignored 忽略判断
  • not_empty 非空判断
  • not_null 非NULL判断

这四种策略既可以配置全局,也可以在实体的注解上配置,但是,配置之后就是死的玩意,无法动态。

一般默认情况下都是not_null,如果此时要更新为null,那么用lambdaUpdateWrapper手动设置哪些字段需要更新为null:
如将userName字段更新为null

userService.update(Wrappers.lambdaUpdate(user).set(User::getUserName, null).eq(User::getId,"0001"));

很显然字段较少时这个方案还能说的过去,但是我们既有很少字段的情况,也有大批量字段的情况
所以此时使用这种方案很明显的使用起来非常难受,那么有没有方案既能支持有值更新,又能支持指定更新,还能
支持全量更新呢?
答案是有的,提供一个最低成本的适配方案如下

方案一

全局设置字段策略为not_null
因为本身LambdaUpdateWrapper 已经满足了单个设置的需求,所以我们在写个方法把全部字段组装起来即可,
当然此处的全部字段肯定也不是真的全部字段比如:一些比较特别的字段就不能被更新为null

  • 公共的字段创建时间,更新时间,逻辑删除字段等等。
public class WrappersFactory {private final static List<String> ignoreList = new ArrayList<>();static {ignoreList.add(CommonField.available);ignoreList.add(CommonField.create_time);ignoreList.add(CommonField.create_username);ignoreList.add(CommonField.update_time);ignoreList.add(CommonField.update_username);ignoreList.add(CommonField.create_user_code);ignoreList.add(CommonField.update_user_code);ignoreList.add(CommonField.deleted);}public static <T> LambdaUpdateWrapper<T> updateWithNullField(T entity) {UpdateWrapper<T> updateWrapper = new UpdateWrapper<>();List<Field> allFields = TableInfoHelper.getAllFields(entity.getClass());MetaObject metaObject = SystemMetaObject.forObject(entity);for (Field field : allFields) {if (!ignoreList.contains(field.getName())) {Object value = metaObject.getValue(field.getName());updateWrapper.set(StringUtils.camelToUnderline(field.getName()), value);}}return updateWrapper.lambda();}}

使用

userService.update(WrappersFactory.updateWithNullField(user).eq(User::getId,"0001"));

方案二

此方案采用的是常规的mybatis-plus扩展
实际就是实现 IsqlInjector

定义个方法

public class UpdateWithNull extends AbstractMethod {@Overridepublic MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {//具体的字段逻辑在这里处理,实际上就是在这里构造一个新的statementreturn null;}
}

定义个CommonMapper继承自BaseMapper,然后让你的所有Mapper继承自CommonMapper

public interface CommonMapper <T> extends BaseMapper<T> {/*** 根据 whereEntity 条件,更新记录** @param entity        实体对象 (set 条件值,可以为 null)* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)*/int updateWithNull(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);}

声明一个IsqlInjector,然后将其配置为spring的bean即可

public class CustomSqlInjector extends AbstractSqlInjector {@Overridepublic List<AbstractMethod> getMethodList() {return Stream.of(new Insert(),new Delete(),new DeleteByMap(),new DeleteById(),new DeleteBatchByIds(),new Update(),new UpdateWithNull(),new UpdateById(),new SelectById(),new SelectBatchByIds(),new SelectByMap(),new SelectOne(),new SelectCount(),new SelectMaps(),new SelectMapsPage(),new SelectObjs(),new SelectList(),new SelectPage()).collect(toList());}
}

方案二个人认为没有什么必要,这种扩展方式是为了增加一些mybatis-plus未支持的定式需求。而我们的目标相对简单,所以使用方案一更高效。

方案二原理介绍

TableFieldInfo#getSqlSet

public String getSqlSet(final String prefix) {final String newPrefix = prefix == null ? EMPTY : prefix;// 默认: column=String sqlSet = column + EQUALS;if (StringUtils.isNotEmpty(update)) {sqlSet += String.format(update, column);} else {sqlSet += SqlScriptUtils.safeParam(newPrefix + el);}sqlSet += COMMA;if (fieldFill == FieldFill.UPDATE || fieldFill == FieldFill.INSERT_UPDATE) {// 不进行 if 包裹return sqlSet;}return convertIf(sqlSet, newPrefix + property);}

可以看到这段代码的逻辑中有一行fieldFill判断,为update或者insert_update时不进行if包裹。我们能可以利用这个特性。直接将需要的非公共字段全部设置为FieldFill.UPDATE即可。

final List<TableFieldInfo> fieldList = tableInfo.getFieldList();for (final TableFieldInfo tableFieldInfo : fieldList) {final Class<? extends TableFieldInfo> aClass = tableFieldInfo.getClass();try {final Field fieldFill = aClass.getDeclaredField("fieldFill");fieldFill.setAccessible(true);fieldFill.set(tableFieldInfo, FieldFill.UPDATE);} catch (final NoSuchFieldException e) {log.error("获取fieldFill失败", e);} catch (final IllegalAccessException e) {log.error("设置fieldFill失败", e);}}

所以这里的具体逻辑为

@Slf4j
public class UpdateWithNull extends AbstractMethod {@Overridepublic MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {SqlMethod sqlMethod = SqlMethod.UPDATE;final List<TableFieldInfo> fieldList = tableInfo.getFieldList();for (final TableFieldInfo tableFieldInfo : fieldList) {final Class<? extends TableFieldInfo> aClass = tableFieldInfo.getClass();try {final Field fieldFill = aClass.getDeclaredField("fieldFill");fieldFill.setAccessible(true);fieldFill.set(tableFieldInfo, FieldFill.UPDATE);} catch (final NoSuchFieldException e) {log.error("获取fieldFill失败", e);} catch (final IllegalAccessException e) {log.error("设置fieldFill失败", e);}}String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(),sqlSet(true, true, tableInfo, true, ENTITY, ENTITY_DOT),sqlWhereEntityWrapper(true, tableInfo));SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);return addUpdateMappedStatement(mapperClass, modelClass, sqlMethod.getMethod(), sqlSource);}
}

相关文章:

让mybatis-plus支持null字段全量更新

文章目录背景方案一使用方案二方案二原理介绍背景 如果仅仅只是标题所列的目标&#xff0c;那么mybatis-plus 中可以通过设置 mybatis-plus.global-config.db-config.field-strategyignored 来忽略null判断&#xff0c;达到实体字段为null时也可以更新数据为null 但是一旦使用…...

MASA Stack 1.0 发布会讲稿——生态篇

2022年运营回顾 贡献者 首先感谢贡献者们为MASA Stack社区所作的积极贡献&#xff0c;这些贡献者给我们提出了很多宝贵的建议&#xff0c;更是积极的提交PR帮助我们一起让产品更健壮&#xff0c;更完善&#xff0c;还在各种场合推广我们的解决方案&#xff0c;非常给力&#x…...

华为OD机试 - 火星文计算2(JS)| 真题+思路++考点+代码

火星文计算2 题目 已知火星人使用的运算符号为#;$ 其与地球人的等价公式如下 x#y4*x3*y2 x$y2*xy3 x y是无符号整数 地球人公式按照c语言规则进行计算 火星人公式中#符优先级高于$ 相同的运算符按从左到右的顺序运算 输入 火星人字符串表达式结尾不带回车换行 输入的字符串…...

从春节后央行的首批罚单,看金融反欺诈反洗钱的复杂性

目录 个人信息保护的问题 征信管理的问题 反洗钱与反欺诈的问题 金融欺诈愈加复杂多变 金融机构如何增强反欺诈反洗钱 春节后&#xff0c;央行公示首批罚单。其中&#xff0c;厦门银行被中国人民银行福州中心支行给予警告&#xff0c;并没收违法所得767.17元&#xff0c;处…...

【Hello Linux】Linux工具介绍 (yum vim)

作者&#xff1a;小萌新 专栏&#xff1a;Linux 作者简介&#xff1a;大二学生 希望能和大家一起进步&#xff01; 本篇博客简介&#xff1a;介绍Linux的常用工具 yum和vim Linux工具介绍Linux中的软件管理工具 -- yum在windows下安装软件的方式在Linux下安装软件的方式认识yum…...

多种充电模式_手持无线充气泵方案

一、手持无线充气泵手持无线充气泵是一个通过锂电池供电达到无需插电就能使用的便携式充气泵&#xff0c;它的适用场景大部分是为身处户外没有办法接通电源的人而设计的&#xff0c;方便人们的出行也可解燃眉之急。不仅如此&#xff0c;为预防手持无线充气泵的锂电池电量用完而…...

【网络基础】DNS是什么

本文不会直接引入复杂枯燥概念&#xff0c;用形象例子通俗讲解&#xff0c;旨在入门理解。 DNS作用 DNS是用来做域名解析的。 相当于把网址翻译成实际ip地址&#xff0c;供其他设备访问。 一个例子 有一个网站的服务器IP地址为1.1.1.1&#xff0c;用电脑访问该网站的话只需…...

二叉树的性质与推导及常见习题整理

目录 一、性质推导 二、常见的二叉树性质习题 1. 某二叉树共有 399 个结点&#xff0c;其中有 199 个度为 2 的结点&#xff0c;则该二叉树中的叶子结点数为&#xff08;&#xff09;。 2.在具有 2n 个结点的完全二叉树中&#xff0c;叶子结点个数为&#xff08;&#xff…...

亚马逊卖家测评补单的重要性和缺点

对于亚马逊、沃尔玛、ebay、wish、newegg、速卖通、阿里国际站、shopee、lazada、temu、乐天、toktok、joom、ozon等卖家来说&#xff0c;测评补单是一个比较常见的话题&#xff0c;因为测评可以给自己产品留下优质的评价&#xff0c;让国外真实买家更加明确&#xff0c;便捷的…...

Java类和对象超详细整理,适合新手入门

目录 一、驼峰命名法 二、Java注释 三、转义符 四、Java程序它的基本结构是什么&#xff1f; 五、Java中的类 六、创建类 七、定义main方法 八、执行代码输出语句 九、Java中的对象 十、创建对象 十一、类与对象的关系 一、驼峰命名法 包名&#xff1a;多单词组成所…...

MySQL:连explain的type类型都没搞清楚,怎敢说精通SQL优化?

我们在使用SQL语句查询表数据时&#xff0c;提前用explain进行语句分析是一个非常好的习惯。通过explain输出sql的详细执行信息&#xff0c;就可以针对性的进行sql优化。 今天我们来分析一下&#xff0c;在explain中11种不同type代表的含义以及其应用场景。 1&#xff0c;sys…...

6.11 极分解

文章目录计算方法代码实现计算方法 一个复数可以写成极坐标形式:zreiθzre^{i\theta}zreiθ.这种分解&#xff0c;左边代表长度&#xff0c;右边代表角度。由此为灵感来源&#xff0c;前人对矩阵也有类似的分解。就是猜想一个线性变换对矩阵的作用&#xff0c;是不是可以分解为…...

Spring、SpringMVC、Shiro、Maven

一、SpringSpring是一个为了解决企业应用程序开发复杂性而创建的开源框架&#xff0c;其核心是IOC–控制反转、AOP–面向切面编程。框架的主要优势之一就是其分层架构&#xff08;WEB层&#xff08;springMvc&#xff09;、业务层&#xff08;Ioc&#xff09;、持久层&#xff…...

element-plus 使用笔记

npm install element-plus --save自动导入 npm install -D unplugin-vue-components unplugin-auto-import// vite.config.jsimport AutoImport from unplugin-auto-import/vite import Components from unplugin-vue-components/vite import { ElementPlusResolver } from …...

《蓝桥杯每日一题》 前缀和·Acwing 3956. 截断数组

1.题目https://www.acwing.com/problem/content/3959/给定一个长度为 n 的数组a1,a2,…,an。现在&#xff0c;要将该数组从中间截断&#xff0c;得到三个非空子数组。要求&#xff0c;三个子数组内各元素之和都相等。请问&#xff0c;共有多少种不同的截断方法&#xff1f;输入…...

促进关键软件高层次人才培养:平凯星辰与华东师范大学签订联合博士培养合作协议

2022 年年初&#xff0c;平凯星辰入选首批工信部教育部支持联合培养国家关键软件高层次人才计划。该计划旨在探索关键软件产教融合育人模式&#xff0c;超常规加快培养一批急需高层次人才&#xff0c;以及探索关键软件联合技术攻关新模式。2022 年年底&#xff0c;在该计划下 平…...

Java程序员的日常——经验贴

关于文件的解压和压缩 如果你的系统不支持tar -z命令 前往讨论 如果是古老的Unix系统&#xff0c;可能并不认识tar -z命令&#xff0c;因此如果你想要压缩或者解压tar.gz的文件&#xff0c;就需要使用gzip或者gunzip以及tar命令了。 关于tar.gz可以这么理解&#xff0c;tar结…...

电商API社区,商品数据,关键词搜索等

1. 需要做的事情 l 商品详情页实现 1、商品查询服务事项 2、商品详情展示 3、添加缓存 2. 实现商品详情页功能 2.1. 功能分析 1、Taotao-portal接收页面请求&#xff0c;接收到商品id。 2、调用taotao-rest提供的商品详情的服务&#xff0c;把商品id作为参数传递给服务。接…...

LEADTOOLS 22.0.6 UPDATE-Crack

OCR SDK 库 许多 OCR 增强功能 LEAD 行业领先的人工智能 OCR SDK 在以下方面获得了显着的识别优化&#xff1a;斜体、大写和小写字母、文本行组装和单词构建、列检测、基线检测和文本行分割。 LEADTOOLS为.NET 6、. NET Framework、Xamarin、UWP、C#、VB、C/C、Java、Objective…...

什么是OJ? 东方博宜题库部分题解

什么是OJ ? Online Judge 比如这样的:Home - 一本通OJ Q:这个在线裁判系统使用什么样的编译器和编译选项? A:系统运行于Debian/Ubuntu Linux. 使用GNU GCC/G++ 作为C/C++编译器, C: gcc Main.c -o Main -fno-asm -O2 -Wall -lm --static -std=c99 -DONLINE_JUDGE C++: g++ …...

别再只盯着应力云图了!用ANSYS Workbench的‘圣维南原理’和模型简化,把你的计算效率提升200%

别再只盯着应力云图了&#xff01;用ANSYS Workbench的‘圣维南原理’和模型简化&#xff0c;把你的计算效率提升200% 有限元分析工程师常常陷入一个误区&#xff1a;认为模型越精细&#xff0c;结果越准确。但现实情况是&#xff0c;一个未经合理简化的复杂模型不仅会消耗大量…...

企业采购AI升级:需求驱动的智能供应商匹配实战

工业数字化与 AI 技术深度融合的当下&#xff0c;传统采购招标模式的短板愈发凸显。众多 Java 架构的企业采购系统仍停留在人工化、经验化运营阶段&#xff0c;供应商管理效率低、匹配精准度不足、人力成本居高不下。依托JBoltAI企业级 Java AI 应用开发框架所倡导的 AIGS 人工…...

如何做谷歌SEO排名优化?搞定高质量外链的4种高成功率技巧

很多刚接触谷歌SEO的朋友发现&#xff0c;自己的网站内容写了不少&#xff0c;可排名始终在搜索结果的五六页开外晃悠。排除掉网站技术层面的小毛病&#xff0c;最让大家头疼的往往就是外链。你可以把外链看作是其他网站给你的“信任投票”&#xff0c;如果投给你的都是些街边的…...

2026程序员危机:AI岗位暴涨12倍,传统开发即将“毕业”?转型AI大模型开发,才是破局关键!

2026年技术圈将面临巨大变革&#xff0c;AI岗位需求激增&#xff0c;传统编程岗位面临淘汰风险。企业更看重懂AI、能提效的复合型人才。程序员需转型AI大模型开发&#xff0c;掌握系统设计、代码审查及AI工具应用能力。北大青鸟推出AI大模型开发实战营&#xff0c;聚焦落地开发…...

开源情报工具Openeir:自动化资产发现与关联分析实战指南

1. 项目概述&#xff1a;一个开源情报&#xff08;OSINT&#xff09;工具的诞生与使命 在信息爆炸的时代&#xff0c;数据本身不再是稀缺品&#xff0c;如何从海量、异构、碎片化的公开信息中&#xff0c;精准、高效地提取出有价值的情报&#xff0c;才是真正的挑战。无论是安全…...

Sora 2如何“唤醒”3D Gaussian Splatting?:从神经辐射场到毫秒级动态场景生成的4层技术跃迁解析

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;Sora 2与3D Gaussian Splatting融合的范式革命 传统视频生成模型受限于体素网格或NeRF隐式表示的计算开销与几何保真度瓶颈&#xff0c;而Sora 2通过引入时空一致性token压缩机制&#xff0c;与3D Gaus…...

Steam SDK上传游戏包体避坑指南:路径、验证码与BuildID那些事儿

Steam SDK上传游戏包体避坑指南&#xff1a;路径、验证码与BuildID那些事儿 第一次通过Steam SDK上传游戏包体时&#xff0c;开发者往往会遇到各种意料之外的"坑"。这些看似小问题却可能导致数小时的无效排查。本文将从实战角度&#xff0c;分享那些官方文档没细说但…...

告别硬编码!SAP ABAPer必学的5个POPUP函数实战用法(附完整代码)

告别硬编码&#xff01;SAP ABAPer必学的5个POPUP函数实战用法&#xff08;附完整代码&#xff09; 在SAP ABAP开发中&#xff0c;交互设计往往决定了用户体验的好坏。想象一下这样的场景&#xff1a;用户在执行关键操作时缺乏明确确认&#xff0c;导致数据误删&#xff1b;或者…...

Linux操作系统软件编程——多线程

什么是线程线程的定义是轻量级的进程&#xff0c;可以实现多任务的并发。线程是操作系统任务调度的最小单位&#xff0c;一个进程至少有一个线程线程的创建由某个进程创建&#xff0c;且进程创建线程时&#xff0c;会为其分配独立的栈区空间&#xff08;默认8M&#xff09;。线…...

小白程序员必看:收藏这份AI黑话指南,轻松入门大模型世界!

本文用大白话解释了AI领域几个核心概念&#xff1a;AI是总称&#xff0c;LLM是推理模型&#xff0c;Agent能独立执行任务&#xff0c;MCP是标准化接口&#xff0c;Skills是技能包。文章通过生活化比喻和实例&#xff0c;帮助读者理解这些概念如何协同工作&#xff0c;实现高效自…...