再数据同步或者幂等场景下,常常需要设置唯一索引来避免重复请求,
select and update
效率低,且并发时还是会报错,并不友好,那么可以用Mysql的Insert ignore语法来优化。
MybatisPlus官方并没有针此处场景进行支持
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
<exclusions>
<exclusion>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
</exclusion>
</exclusions>
</dependency>
三、注入自定义批量插入sql
因为只需要改造insertBatchSomeColumn
方法,那直接CV就好
insertBatchSomeColumn
方法属于mybatis plus
官方扩展包中
sql模板
public class InsertIgnoreBatchAllColumn extends AbstractMethod {
* mapper 对应的方法名
private static final String MAPPER_METHOD = "insertIgnoreBatchAllColumn";
* 字段筛选条件
@Setter
@Accessors(chain = true)
private Predicate<TableFieldInfo> predicate;
@SuppressWarnings("Duplicates")
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
KeyGenerator keyGenerator = new NoKeyGenerator();
SqlMethod sqlMethod = SqlMethod.INSERT_ONE;
String sqlTemplate = "<script>\nINSERT IGNORE INTO %s %s VALUES %s\n</script>";
List<TableFieldInfo> fieldList = tableInfo.getFieldList();
String insertSqlColumn = tableInfo.getKeyInsertSqlColumn(false) +
this.filterTableFieldInfo(fieldList, predicate, TableFieldInfo::getInsertSqlColumn, EMPTY);
String columnScript = LEFT_BRACKET + insertSqlColumn.substring(0, insertSqlColumn.length() - 1) + RIGHT_BRACKET;
String insertSqlProperty = tableInfo.getKeyInsertSqlProperty(ENTITY_DOT, false) +
this.filterTableFieldInfo(fieldList, predicate, i -> i.getInsertSqlProperty(ENTITY_DOT), EMPTY);
insertSqlProperty = LEFT_BRACKET + insertSqlProperty.substring(0, insertSqlProperty.length() - 1) + RIGHT_BRACKET;
String valuesScript = SqlScriptUtils.convertForeach(insertSqlProperty, "list", null, ENTITY, COMMA);
String keyProperty = null;
String keyColumn = null;
// 表包含主键处理逻辑,如果不包含主键当普通字段处理
if (StringUtils.isNotEmpty(tableInfo.getKeyProperty())) {
if (tableInfo.getIdType() == IdType.AUTO) {
/* 自增主键 */
keyGenerator = new Jdbc3KeyGenerator();
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
} else {
if (null != tableInfo.getKeySequence()) {
keyGenerator = TableInfoHelper.genKeyGenerator(tableInfo, builderAssistant, sqlMethod.getMethod(), languageDriver);
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
String sql = String.format(sqlTemplate, tableInfo.getTableName(), columnScript, valuesScript);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return this.addInsertMappedStatement(mapperClass, modelClass, MAPPER_METHOD, sqlSource, keyGenerator, keyProperty, keyColumn);
注入sql
public class CustomerSqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
methodList.add(new InsertIgnoreBatchAllColumn());
return methodList;
通用mapper
public interface CommonMapper<T> extends BaseMapper<T> {
* 全量插入,等价于insert,忽略唯一索引冲突的行
* {@link InsertIgnoreBatchAllColumn}
* @param entityList
* @return
int insertIgnoreBatchAllColumn(List<T> entityList);
通用Service
public class CommonServiceImpl<M extends CommonMapper<T>, T> extends ServiceImpl<M, T> {
@Transactional(rollbackFor = Exception.class)
public boolean fastSaveIgnoreBatch(List<T> list, int batchSize) {
if(CollectionUtils.isEmpty(list)) {
return true;
batchSize = batchSize < 1 ? BATCH_SIZE : batchSize;
if(list.size() <= batchSize) {
return retBool(baseMapper.insertIgnoreBatchAllColumn(list));
for (int fromIdx = 0 , endIdx = batchSize ; ; fromIdx += batchSize, endIdx += batchSize) {
if(endIdx > list.size()) {
endIdx = list.size();
baseMapper.insertIgnoreBatchAllColumn(list.subList(fromIdx, endIdx));
if(endIdx == list.size()) {
return true;
@Transactional(rollbackFor = Exception.class)
public boolean fastSaveIgnoreBatch(List<T> list) {
return fastSaveIgnoreBatch(list, BATCH_SIZE);
开源日报 | 通用端到端OCR模型开源;Cassandra 5.0正式GA;NGINX迁移到GitHub;iPhone 16全系列配备8GB RAM;国产数据库100%替代走到哪了?
NGINX 项目迁移到 GitHub
完整的数仓能力,字节云原生开源数仓 ByConity 1.0 版本发布!
Redox OS 0.9.0 版本发布:开源操作系统迎来重大更新
当《黑神话:悟空》遇上 openKylin,国产力量的极致碰撞!
PublicCMS 202406.e 更新,新增字体加密敏感词替换等
开源 OA 办公系统 — 勾股 OA 5.1.2 新版发布
Xinference v0.15.0 版本飞跃:自定义模型能力再升级,重塑 AI 交互体验
Rust 日志库 tklog v0.2.0 :支持设置日志级别独立日志文件
别再 mybatis 了,融合 JPA 和超强查询的 sqltoy-orm 5.6.22 发版
:fire::fire::fire:超级 ORM 框架 mybatis-mp 1.6.7 正式发布
Apple Intelligence 将于下月起登陆 iPhone、iPad 与 Mac
Apache Cassandra 5.0 正式 GA,带来向量搜索、JDK 17 支持、存储附加索引等功能
Apple 推出 iPhone 16 系列新产品
【视频】Solon Cloud Gateway: Helloworld (代理 Solon 官网)
域名证书检测平台 Domain Admin 加入 Dromara 开源社区
ActiveReports 报表应用教程 (15)---报表换肤
Html5 FileReader 对文件进行Base64编码
Wijmo 更优美的jQuery UI部件集:通过jsFiddle测试Wijmo Gauges
ActiveReports 报表应用教程 (8)---交互式报表之动态过滤
ActiveReports 报表应用教程 (16)---报表导出
C#性能优化实践
ActiveReports 报表应用教程 (7)---交叉报表及数据透视图实现方案
2013 北京 QCon热点分享
ActiveReports 报表应用教程 (9)---交互式报表之动态排序
ASP.NET MVC 5 - 验证编辑方法(Edit method)和编辑视图(Edit view)
Spread for Windows Forms快速入门(4)---常用的单元格类型(上)
带你走近AngularJS - 基本功能介绍
如何选择高性价比的控件产品
Table-values parameter(TVP)系列之三: 利用Collection将其作为参数传给SP
TX Text Control文字处理教程(4)标记文本域
分享自制的C#和VB Code互转工具
程序员级别鉴定书(.NET面试问答集锦)
ActiveReports 报表应用教程 (14)---数据可视化
TechED2010与我(一)―― 初来乍到
Silverlight 5 深入理解 - TechEd2011葡萄城讲师课程
基于Html5的Canvas实现的Clocks (钟表)
如何遍历当前进程中的AppDomain
第十一届GPCT杯大学生程序设计大赛完美闭幕
如何在ASP.NET中生成HTML5离线Web应用
开发了一个一起听歌聊天的开源项目
分享自制的C#和VB Code互转工具
也许跟大家不太一样,我是这么用TypeScript来写前端的
用SwiftUI开发了一个Gitee在iOS上的App
不太一样的前端开发之TypeScript装饰器和面向对象
如何在ASP.NET中生成HTML5离线Web应用
Silverlight自定义数据绑定控件应该如何处理IEditableObject和IEditableCollectionView对象
MultiRow中文版技术白皮书
2013 北京 QCon热点分享
如何把Excel中的单元格等对象保存成图片
MultiRow发现之旅(一)- 高效模板设计器
Spread for Windows Forms快速入门(13)---数据排序
Spread for Windows Forms快速入门(5)---常用的单元格类型(下)
如何雇人的十五条建议
vscode成功变身社交平台?看我如何给vscode扩展一个聊天室!
Spread for Windows Forms快速入门(15)---使用 Spread 设计器
在 ActiveReports 中嵌入 Spread 控件
MultiRow发现之旅(五)- MultiRow版俄罗斯方块(exe + 源码)
“云”随我动近在咫尺 - 中小企业如何看待云计算?
用于 Windows8 的 Wijmo Charts 图表控件
如何把Excel中的单元格等对象保存成图片
新写了一个基于MacOS设计的WebUI
用代码聊聊我们跟目前主流前端编程不一样的地方
SwiftUI在iOS上NavigationBar标题重影问题复现
TX Text Control文字处理教程(2)- 文件操作
TechED2010与我(一)―― 初来乍到
在 ActiveReports 中嵌入 Spread 控件
一套内容采集系统 解放编辑人员
BBBUG音乐聊天室的开发故事和架构设计
【技术维新 践行精彩】移动互联时代的研发利器
分享ISTQB培训体验
Spread for Windows Forms高级主题(7)---自定义打印的外观
Wijmo 更优美的jQuery UI部件集:运行时处理Wijmo GridView数据操作
MultiRow发现之旅(一)- 高效模板设计器
Nginx反向代理其他站并替换关键词遇到的坑
基于装饰器-我又是这么用TypeScript处理表格配置的
域名-DDNS-内网穿透-端口转发-DNS的一些小常识
在Silverlight中动态绑定页面报表(PageReport)的数据源
Spread for Windows Forms高级主题(6)---数据绑定管理
免装软件和服务,使用SSH实现内网穿透并反向代理
ActiveReports 报表应用教程 (15)---报表换肤
基于装饰器-我是这么处理TypeScript项目数据转换的
应用系统中常见报表类型解析
TX Text Control文字处理教程(7)邮件合并
ASP.NET MVC 5 - 查询Details和Delete方法
Spread for Windows Forms高级主题(1)---底层模型
Nginx实现Java服务API接口的开发阶段高可用
Spread for Windows Forms高级主题(4)---自定义用户交互
Wijmo 更优美的jQuery UI部件集:爱上 ThemeRoller
Spread for Windows Forms快速入门(7)---单元格的交互操作
ASP.NET MVC 5 - 给电影表和模型添加新字段
响应式设计(Response Web Design)浅谈
Spread for Windows Forms快速入门(13)---数据排序
TX Text Control文字处理教程(13)实现拖放操作
Spread for WinRT 7新功能使用指南
WPF的消息机制(三)- WPF内部的5个窗口之处理激活和关闭的消息窗口以及系统资源通知窗口