【精品】通用Mapper 批量更新bug解决方案
问题描述
环境:mysql8.x+mybatis3.5.13+tk.mybatis4.2.3
在使用tk.mybatis做批量更新时,程序会报错,说是执行的SQL语法错误,经研究源代码发现tk.mybatis在实现批量更新时是通过多次执行update语句实现的。这本身就不符合MySQL批量更新的语法,可以通过自定义Mapper的方式解决。
有关MySQL批量更新SQL语句的语法请参考:MySQL专有的SQL语句
解决方案
批量更新
- 接口
@RegisterMapper
public interface BatchUpdateByIdMapper<T> {/*** 批量更新* @param list* @return*/@UpdateProvider(type = BatchUpdateByIdProvider.class, method = "dynamicSQL")int batchUpdate(List<T> list);
}
- provider
public class BatchUpdateByIdProvider extends MapperTemplate {public BatchUpdateByIdProvider(Class<?> mapperClass, MapperHelper mapperHelper) {super(mapperClass, mapperHelper);}public String batchUpdate(MappedStatement statement) {//1.获取实体类对应的Class对象Class<?> entityClass = super.getEntityClass(statement);//2.获取实体类在数据库中对应的表名String tableName = super.tableName(entityClass);//3.生成update子句String update = SqlHelper.updateTable(entityClass, tableName);//4.创建StringBuilder用于拼接SQL语句的各个组成部分StringBuilder sb = new StringBuilder(update);sb.append("<trim prefix=\"set\" suffixOverrides=\",\">");//5.获取所有字段信息Set<EntityColumn> columns = EntityHelper.getColumns(entityClass);//获取主键EntityColumn pkEntityColumn = null;for (EntityColumn entityColumn : columns) {boolean isPrimaryKey = entityColumn.isId();if (isPrimaryKey) {pkEntityColumn = entityColumn;break;}}for (EntityColumn entityColumn : columns) {boolean isPrimaryKey = entityColumn.isId();//6.判断当前字段是否为主键if (!isPrimaryKey) {//7.使用非主键字段拼接SET子句String columnHolder = entityColumn.getColumnHolder("item");sb.append("<trim prefix=\"").append(entityColumn.getColumn()).append("= case\" suffix=\"end, \">");sb.append("<foreach collection=\"list\" index=\"index\" item=\"item\">");sb.append(" when ").append(pkEntityColumn.getColumn()).append(" = ").append(pkEntityColumn.getColumnHolder("item")).append(" then ").append(columnHolder);sb.append("</foreach>");sb.append("</trim>");}}sb.append("</trim>");//10.使用前面缓存的主键名、主键值拼接where子句sb.append("where ").append(pkEntityColumn.getColumn()).append(" in ");sb.append("<foreach close=\")\" collection=\"list\" item=\"item\" open=\"(\" separator=\", \">");sb.append(" #{item.").append(pkEntityColumn.getProperty()).append("}");sb.append("</foreach>");//11.将拼接好的字符串返回return sb.toString();}}
选择性批量更新
- Mapper接口
@RegisterMapper
public interface BatchUpdateSelectiveByIdMapper<T> {/*** 选择性批量更新* @param list* @return*/@UpdateProvider(type = BatchUpdateSelectiveByIdProvider.class, method = "dynamicSQL")int batchUpdateSelective(List<T> list);
}
- provider
public class BatchUpdateSelectiveByIdProvider extends MapperTemplate {public BatchUpdateSelectiveByIdProvider(Class<?> mapperClass, MapperHelper mapperHelper) {super(mapperClass, mapperHelper);}/*** 批量更新* @param statement* @return*/public String batchUpdateSelective(MappedStatement statement) {//1.获取实体类对应的Class对象Class<?> entityClass = super.getEntityClass(statement);//2.获取实体类在数据库中对应的表名String tableName = super.tableName(entityClass);//3.生成update子句String update = SqlHelper.updateTable(entityClass, tableName);//4.创建StringBuilder用于拼接SQL语句的各个组成部分StringBuilder sb = new StringBuilder(update);sb.append("<trim prefix=\"set\" suffixOverrides=\",\">");//5.获取所有字段信息Set<EntityColumn> columns = EntityHelper.getColumns(entityClass);//获取主键EntityColumn pkEntityColumn = null;for (EntityColumn entityColumn : columns) {boolean isPrimaryKey = entityColumn.isId();if (isPrimaryKey) {pkEntityColumn = entityColumn;break;}}for (EntityColumn entityColumn : columns) {boolean isPrimaryKey = entityColumn.isId();//6.判断当前字段是否为主键if (!isPrimaryKey) {//7.使用非主键字段拼接SET子句String columnHolder = entityColumn.getColumnHolder("item");sb.append("<trim prefix=\"").append(entityColumn.getColumn()).append("= case\" suffix=\"end, \">");sb.append("<foreach collection=\"list\" index=\"index\" item=\"item\">");sb.append("<if test=\"item.").append(entityColumn.getProperty()).append(" != null\"> ");sb.append(" when ").append(pkEntityColumn.getColumn()).append(" = ").append(pkEntityColumn.getColumnHolder("item")).append(" then ").append(columnHolder);sb.append(" </if>");sb.append("</foreach>");sb.append("</trim>");}}sb.append("</trim>");//10.使用前面缓存的主键名、主键值拼接where子句sb.append("where ").append(pkEntityColumn.getColumn()).append(" in ");sb.append("<foreach close=\")\" collection=\"list\" item=\"item\" open=\"(\" separator=\", \">");sb.append(" #{item.").append(pkEntityColumn.getProperty()).append("}");sb.append("</foreach>");//11.将拼接好的字符串返回return sb.toString();}}
测试代码
@Test
void batchUpdate(){List<Subject> list = List.of(Subject.builder().id(13L).name("111").build(),Subject.builder().id(14L).name("222").build(),Subject.builder().id(15L).name("333").build(),Subject.builder().id(16L).name("444").build());subjectMapper.batchUpdateSelective(list);
}
相关文章:
【精品】通用Mapper 批量更新bug解决方案
问题描述 环境:mysql8.xmybatis3.5.13tk.mybatis4.2.3 在使用tk.mybatis做批量更新时,程序会报错,说是执行的SQL语法错误,经研究源代码发现tk.mybatis在实现批量更新时是通过多次执行update语句实现的。这本身就不符合MySQL批量…...
腾讯mini项目-【指标监控服务重构-会议记录】2023-07-06
7/6 会议记录 Profile4个步骤 解压kafka消息初始化性能事件,分析事件将数据写入kafkaRun 开始执行各stage handler 上报耗时到otel-collector。。。 // ConsumerDispatchHandler consumer // // param msg *sarama.ConsumerMessage // param consumer *databus.K…...
【React】函数式组件和类式组件的用法和逻辑
组件的使用 当应用是以多组件的方式实现,这个应用就是一个组件化的应用 注意: 组件名必须是首字母大写虚拟DOM元素只能有一个根元素虚拟DOM元素必须有结束标签 < /> 渲染类组件标签的基本流程React 内部会创建组件实例对象调用render()得到虚拟 …...
题目 1061: 二级C语言-计负均正
从键盘输入任意20个整型数,统计其中的负数个数并求所有正数的平均值。 保留两位小数 样例输入 1 2 3 4 5 6 7 8 9 10 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 样例输出 10 5.50 解题思路: 如题所示,输入20个正负数,---》求付数的个…...
数位和(C++)
系列文章目录 进阶的卡莎C++_睡觉觉觉得的博客-CSDN博客数1的个数_睡觉觉觉得的博客-CSDN博客双精度浮点数的输入输出_睡觉觉觉得的博客-CSDN博客足球联赛积分_睡觉觉觉得的博客-CSDN博客大减价(一级)_睡觉觉觉得的博客-CSDN博客小写字母的判断_睡觉觉觉得的博客-CSDN博客纸币(…...
[牛客复盘] 牛客周赛round13 20230924
[牛客复盘] 牛客周赛round13 20230924 总结矩阵转置置2. 思路分析3. 代码实现 小红买基金1. 题目描述2. 思路分析3. 代码实现 小红的密码修改1. 题目描述2. 思路分析3. 代码实现 小红的转账设置方式1. 题目描述2. 思路分析3. 代码实现 小红打boss1. 题目描述2. 思路分析3. 代码…...
mybatsi-MyBatis的逆向工程
mybatsi-MyBatis的逆向工程 一、前言二、创建逆向工程的步骤1.添加依赖和插件2.创建MyBatis的核心配置文件3.创建逆向工程的配置文件4.执行MBG插件的generate目标 一、前言 正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。 Hibernate是支…...
转转闲鱼交易猫链接源码 支持二维码收款
最新仿二手闲置链接源码 后台一键生成链接,后台管理教程:解压源码,修改数据库config/Congig 不会可以看源码里有教程 下载程序:https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3...
Python爬虫基础(三):使用Selenium动态加载网页
文章目录 系列文章索引一、Selenium简介1、什么是selenium?2、为什么使用selenium3、安装selenium(1)谷歌浏览器驱动下载安装(2)安装selenium 二、Selenium使用1、简单使用2、元素定位3、获取元素信息4、交互 三、Phan…...
Linux系统下安装Mysql
1、执行命令:rpm -qa | grep -i mysql,先查看系统之前是否有安装相关的rpm包,如果有,会显示类似下面的信息; 2、通过命令yum -y remove mysql-* 一次性删除系统上所有相关的rpm包,或者通过命令yum -y …...
Jenkins学习笔记1
CI 服务器: 认识Jenkins: Jenkins是一个可扩展的持续集成(CI)引擎,是一个开源项目,旨在提供一个开放易用的软件平台,使得软件持续集成变成可能。Jenkins非常易于安装和配置,简单易…...
注意力机制
概念没什么好说的,反正大家都会说,具体实战怎么写才是最为重要的 1.自注意力 假设有一组数据,都是一维的向量,这个向量可能是一个样本,可能是其他什么,都无所谓。 假设有一组一维向量x1,x2,x3,x4,x5; 第…...
JVM-Java字节码技术笔记
Java字节码技术 Java字节码是java代码编译后的中间代码格式,JVM需要读取并解析字节码才能执行相应的任务 获取字节码简介:由单字节(byte)的指令组成 操作码( 指令), 主要由类型前缀和操作名称两部分组成。根据指令的性质…...
C++ 友元、重载、继承、多态
友元 关键字:friend 友元的三种实现 全局函数做友元类做友元成员函数做友元 全局函数做友元 //建筑物类 class Building {//goodGay全局函数是Building好朋友,可以访问Building中私有成员friend void goodGay(Building& building); public:Build…...
Spring Boot 日志文件
前言 本篇博客主要介绍自定义的日志打印、日志的级别高低、如何保存日志等等..... 一、日志是什么?日志有什么用? 日志就是我们控制台上输出的内容,控制台上的输出的信息就是日志信息,如下所示: 日志有什么用&#x…...
vulhub venom
文章目录 靶场环境信息收集ftp服务二、信息利用三、任意文件上传三 sudo提权靶场环境 `vmware 靶场信息:https://www.vulnhub.com/entry/venom-1,701/ 下载地址:https://download.vulnhub.com/venom/venom.zip 新建虚拟机打开下载后的ovf文件 遇见导入失败合规性检查时,重试…...
量化交易之One Piece篇 - linux - 定时任务(重启服务器、执行程序、验证)
linux 执行命令: crontab -e 0 5 * * 1-5 sudo /sbin/shutdown -r now 0 17 * * 1-5 sudo /sbin/shutdown -r now 45 8 * * 1-5 cd /home/ubuntu/onepiece/bin/datacore && ./datacore 45 20 * * 1-5 cd /home/ubuntu/onepiece/bin/datacore && ./datacore 以…...
Qt5开发及实例V2.0-第二十三章-Qt-多功能文档查看器实例
Qt5开发及实例V2.0-第二十三章-Qt-多功能文档查看器实例 第23章 多功能文档查看器实例23.1. 简介23.2. 界面与程序框架设计23.2.1. 图片资源23.2.2. 网页资源23.2.3. 测试用文件 23.3 主程序代码框架23.4 浏览网页功能实现23.4.1 实现HtmIHandler处理器 23.5. 部分代码实现23.5…...
爬虫笔记_
爬虫简介 爬虫初始深入 爬虫在使用场景中的分类 通用爬虫: 抓取系统重要组成部分。抓取的是一整张页面数据 聚焦爬虫: 是建立在通用爬虫的基础上。抓取的是页面中特定的局部内容。 增量式爬虫 监测网站中数据更新的情况。只会抓取网站中最新更新出来的…...
Spring设计模式,事务管理和代理模式的应用
扩充:贝叶斯定理答案见底。 设计模式对关于面向对象问题的具体解决方案. 1,单例多例 在设计单例模式时,要注意两个点 1.构造方法要私有 2.成员变量要私有 3.创建对象所用的方法要被synchronized修饰.(因为方法体中会涉及到判断当…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
libfmt: 现代C++的格式化工具库介绍与酷炫功能
libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库,提供了高效、安全的文本格式化功能,是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全:…...
【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...
算法250609 高精度
加法 #include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<algorithm> using namespace std; char input1[205]; char input2[205]; int main(){while(scanf("%s%s",input1,input2)!EOF){int a[205]…...
Element-Plus:popconfirm与tooltip一起使用不生效?
你们好,我是金金金。 场景 我正在使用Element-plus组件库当中的el-popconfirm和el-tooltip,产品要求是两个需要结合一起使用,也就是鼠标悬浮上去有提示文字,并且点击之后需要出现气泡确认框 代码 <el-popconfirm title"是…...
