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

Mybatis-plus解决兼容oracle批量插入

本博客借鉴网上很多大佬的答案,东拼西凑,最终在项目中完成批量插入,仅供参考~~~

1. 自定义SQL注入器

新建一个名为EasySqlInjector的类,继承DefaultSqlInjector

public class EasySqlInjector extends DefaultSqlInjector {@Overridepublic List<AbstractMethod> getMethodList(Class<?> mapperClass) {// 注意:此SQL注入器继承了DefaultSqlInjector(默认注入器),调用了DefaultSqlInjector的getMethodList方法,保留了mybatis-plus的自带方法List<AbstractMethod> methodList = super.getMethodList(mapperClass);methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));return methodList;}}
2. 将SQL注入器交给Spring容器

MybatisPlusConfig类中,将刚才创建的SQL注入器EasySqlInjector,注册为一个bean。

@EnableTransactionManagement(proxyTargetClass = true)
@Configuration
public class MybatisPlusConfig
{@Beanpublic PaginationInterceptor paginationInterceptor() {PaginationInterceptor paginationInterceptor = new PaginationInterceptor();// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false// paginationInterceptor.setOverflow(false);// 设置最大单页限制数量,默认 500 条,-1 不受限制// paginationInterceptor.setLimit(500);// 开启 count 的 join 优化,只针对部分 left joinpaginationInterceptor.setLimit(-1);
//        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));return paginationInterceptor;}/*** 分页插件,自动识别数据库类型 https://baomidou.com/guide/interceptor-pagination.html*/public PaginationInnerInterceptor paginationInnerInterceptor(){PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();// 设置数据库类型为mysqlpaginationInnerInterceptor.setDbType(DbType.ORACLE);// 设置最大单页限制数量,默认 500 条,-1 不受限制paginationInnerInterceptor.setMaxLimit(-1L);return paginationInnerInterceptor;}/*** 乐观锁插件 https://baomidou.com/guide/interceptor-optimistic-locker.html*/public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor(){return new OptimisticLockerInnerInterceptor();}/*** 如果是对全表的删除或更新操作,就会终止该操作 https://baomidou.com/guide/interceptor-block-attack.html*/public BlockAttackInnerInterceptor blockAttackInnerInterceptor(){return new BlockAttackInnerInterceptor();}@Beanpublic EasySqlInjector sqlInjector() {return new EasySqlInjector();}}
3. 配置EasyBaseMapper继承BaseMapper

新建EasyBaseMapper类,继承BaseMapper,并在此类中配置insertBatchSomeColumn()方法。

/

public interface  EasyBaseMapper<T> extends BaseMapper<T> {/*** @param entityList 实体列表*/void insertBatchSomeColumn(Collection<T> entityList);
}
4.自定义Mybatis拦截器OracleSqlInterceptor

   这个地方要注意,表的主键我用触发器已经自动填入,所以keyGenerator设置为NoKeyGenerator.INSTANCE,这个地方有个坑,不那么设置,SQL一直报错,折腾了两个小时,实际上拼接的SQL没问题

@Component
@Slf4j
@Order(1)
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class OracleSqlInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {//当前业务,兼容pg 和 oracle,需要兼容oracle的批量插入语句StatementHandler statementHandler = (StatementHandler) invocation.getTarget();BoundSql boundSql = statementHandler.getBoundSql();String sql = boundSql.getSql();StatementHandler delegate = (StatementHandler) ReflectUtil.getFieldValue(statementHandler, "delegate");MappedStatement mappedStatement = (MappedStatement) ReflectUtil.getFieldValue(delegate, "mappedStatement");ReflectUtil.setFieldValue(mappedStatement,"keyGenerator", NoKeyGenerator.INSTANCE);String mName  = mappedStatement.getId().substring(mappedStatement.getId().lastIndexOf(".") + 1);if("insertBatchSomeColumn".equals(mName)){//开始兼容批量插入语句,并设置boundSqlField declaredField = boundSql.getClass().getDeclaredField("sql");declaredField.setAccessible(true);declaredField.set(boundSql, convertOracleInsertSql(sql));log.info("---转换后的sql为:{}", boundSql.getSql());}return invocation.proceed();}/*** Oracle Insert语句转化** @param sql 传入的pg的sql* @return 转化后的sql*/public String convertOracleInsertSql(String sql) {//用oracle中的批量语句代替//查找values的位置,将后面全部括号里的东西取出,然后再用对应的数据进行封装//获取前面的sql,这段sql与Oracle的相同String prefix = sql.substring(0, getKeywordValueIndex(sql));//排除table中的括号,取后面的括号String subSql = sql.substring(getKeywordValueIndex(sql));String valueSql = subSql.substring(subSql.indexOf("("));List<String> valueList = getValues(valueSql);//拼接sqlStringBuilder sqlBuilder = new StringBuilder().append(prefix);//sqlBuilder.append("SELECT A.* FROM (");String selectValue = "SELECT ";String endValue = " FROM DUAL ";String unionValue = "UNION ALL ";boolean start = true;for (String value : valueList) {if (!start) {sqlBuilder.append(unionValue);}else {start = false;}sqlBuilder.append(selectValue).append(value).append(endValue);}//sqlBuilder.append(") A");return sqlBuilder.toString();}/*** 使用栈实现获取value中括号的值**/public List<String> getValues(String sql) {List<String> values = new ArrayList<>();Stack<Character> brackets = new Stack<>();StringBuilder splitValue = new StringBuilder();for (Character c : sql.toCharArray()) {if ('(' == c) {//左括号进栈brackets.push(c);}else if (')' == c) {//右括号则将左括号出栈,清空builderbrackets.pop();values.add(splitValue.toString());splitValue.delete(0, splitValue.length());}else if (!brackets.empty()) {//只有进入括号中才将值放入,排除括号外的逗号splitValue.append(c);}}return values;}/*** 查找关键字value的位置*/public  int getKeywordValueIndex(String sql) {//先找values,再找valueif (sql.contains("values")) {return sql.indexOf("values");}else if (sql.contains("VALUES")) {return sql.indexOf("VALUES");}else if (sql.contains("value")) {return sql.indexOf("value");}else {return sql.indexOf("VALUE");}}}

然后,用业务Mapper继承EasyBaseMapper就可以调用insertBatchSomeColumn()方法了。

相关文章:

Mybatis-plus解决兼容oracle批量插入

本博客借鉴网上很多大佬的答案&#xff0c;东拼西凑&#xff0c;最终在项目中完成批量插入&#xff0c;仅供参考~~~ 1. 自定义SQL注入器 新建一个名为EasySqlInjector的类&#xff0c;继承DefaultSqlInjector。 public class EasySqlInjector extends DefaultSqlInjector {O…...

Kaggle竞赛——灾难推文分类(Disaster Tweets)

目录 1. 准备工作2. 资源导入3. 数据处理4. 绘制词云图5. 数据可视化5.1 词数和字符数可视化5.2 元特征可视化5.3 类别可视化 6. 词元分析6.1 一元语法统计6.2 多元语法统计 7. 命名实体识别8. 推文主题提取9. 构建模型9.1 数据划分与封装9.2 模型训练与验证 10. 模型评估11. 测…...

SC2601音频编解码器可pin to pin兼容ES8311

SC2601 是一款低功耗单声道音频编解码器&#xff0c;具有全差分输出&#xff0c;支持在全差分配置下可编程模拟输入。可pin to pin兼容ES8311。 录音路径包含一个全差分输入&#xff0c;低噪声可编程增益放大器和自动增益控制&#xff08;ALC&#xff09;。在录音过程中,通过内…...

通用AT指令

1、查询SIM卡状态 ATCPIN?2、查询信号强度 ATCSQ //99,99 表示无信号3、查询IMEI ATCGSN4、查询4G/5G模式 ATCOPS? //7表示在4G模式&#xff0c;13表示在5G模式5、设置接入点 ATCGDCONT1,"IP","uninet" //联通 ATCGDCONT1,"IP","…...

二进制狼群算法

本文所涉及所有资源均在 传知代码平台 可获取。 目录 一、背景及意义介绍 背景 意义...

STL——list的介绍和使用

前言 本篇博客我们继续来介绍STL的内容&#xff0c;这次我们要介绍的是list这个容器&#xff0c;可以简单地理解为顺序表&#xff0c;当然和我们之前学过顺序表还是有区别的&#xff0c;具体内容大家可以继续往下阅读&#xff0c;下面进入正文。 1. list简介 1.list是一种可…...

二百七十六、ClickHouse——Hive和ClickHouse非常不同的DWS指标数据SQL语句

一、目的 在完成数据之后对业务指标进行分析&#xff0c;Hive和ClickHouseSQL真不一样 二、部分业务指标表 2.1 统计数据流量表1天周期 2.1.1 Hive中原有代码 2.1.1.1 Hive中建表语句 --1、统计数据流量表——动态分区——1天周期 create table if not exists hurys_d…...

Elasticsearch Date类型,时间存储相关说明

本文介绍了在SpringBoot中处理Elasticsearch中日期时间格式的问题。当时间输出为UTC格式并存在时区差异时&#xff0c;可通过设置字段格式如yyyy-MM-dd HH:mm:ss并指定时区为GMT8来解决。存储Date类型数据时&#xff0c;可以使用JSON库如json-lib, fastjson, Jackson或gson进行…...

mathorcup2024台风 我all in ai

三个问题&#xff0c;力大砖飞。 不建物理模型&#xff0c;直接all in好吧 第一个故意无监督 第二个LSTMCNN注意力&#xff0c;刚好时间空间 第三个在第二个上加了个transfomer &#xff0c;然后LSTM变双向&#xff0c;增加层数&#xff08;基线模型选的经验公式&#xff0c;少…...

android 10 后台启动activity

摘要&#xff1a;Android 10&#xff08;API 级别 29&#xff09;及更高版本会限制应用何时可以启动 activity 背景。这些限制有助于最大限度地减少对用户的干扰&#xff0c; 让用户能够更好地控制其屏幕上显示的内容。本文以此为出发点&#xff0c;基于展锐平台对系统代码进行…...

文案创作新思路:Python与文心一言API的完美结合

在这个信息爆炸的时代&#xff0c;内容创作似乎成了一项需要魔法才能完成的任务。不过&#xff0c;别担心&#xff01;今天&#xff0c;我们将向你介绍一种新的“魔法”工具——百度文心一言 API。这款大语言模型不仅能与人对话互动&#xff0c;还能高效便捷地协助你获取创意灵…...

CentOS 7 上安装 MySQL 8.0 教程

&#x1f31f; 你好 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…...

Chromium HTML5 新的 Input 类型url对应c++

一、Input 类型: url url 类型用于应该包含 URL 地址的输入域。 在提交表单时&#xff0c;会自动验证 url 域的值。 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>test</title> </head> <body&g…...

java多线程编程(二)一一>线程安全问题, 单例模式, 解决程线程安全问题的措施

引言&#xff1a; 如果多线程环境下代码运行的结果是符合我们预期的&#xff0c;即在单线程环境应该的结果&#xff0c;则说这个程序是线程安全的 线程安全问题的原因&#xff1a; 一.操作系统的随机调度 &#xff1a; 二.多个线程修改同一个变量&#xff1a; 三.修改操作不是…...

Leetcode 213. 打家劫舍 II 动态规划

原题链接&#xff1a;Leetcode 213. 打家劫舍 II class Solution { public:int rob(vector<int>& nums) {int n nums.size();if (n 1)return nums[0];if (n 2)return max(nums[0], nums[1]);// 如果偷了第一家&#xff0c;就不能偷最后一家int dp[n - 1];dp[0] …...

就业市场变革:AI时代,我们将如何评估人才?

内容概要 在这个充满变革的时代&#xff0c;就业市场正被人工智能&#xff08;AI&#xff09;技术深刻改变。随着技术的进步&#xff0c;传统的人才评估方式逐渐显示出其局限性。例如&#xff0c;过去依赖于纸质简历和面试评估的方式在快速变化的环境中难以准确识别真实的人才…...

富格林:安全操作方式稳健出金

富格林认为&#xff0c;黄金一直是吸引投资者关注的投资产品之一&#xff0c;投资者不断踏入黄金投资交易市场。很多投资者都以为现货黄金投资是很容易实现出金获得丰厚利润&#xff0c;但是面对复杂的交易市场&#xff0c;不仅不能轻易实现安全获利出金&#xff0c;甚至可能还…...

早点包子店点餐的软件下载和点餐操作教程 佳易王餐饮点餐管理系统操作方法

一、概述 【软件试用版资源文件可以点文章最后卡片了解】 早点包子店点餐的软件下载和点餐操作教程 适合于早点早餐餐饮行业的软件&#xff0c;实现早点点餐&#xff0c;收银会员管理&#xff0c;库存统计&#xff0c;销售统计等一体化操作。 点餐的时候可以用手触摸点&…...

uniapp一键打包

1.先安装python环境&#xff0c; 2.复制这几个文件到uniapp项目里面 3.修改自己证书路径&#xff0c;配置文件路径什么的 4.在文件夹页面双击buildController.py或者cmd直接输入buildController.py 5.python报错&#xff0c;哪个依赖缺少安装哪个依赖 6.执行不动的话&…...

什么是ksqlDB?流处理世界里的新范式

在大数据技术快速迭代的今天,我们见证了数据处理范式的不断演进。从批处理到流处理,从复杂的编程框架到声明式API,技术在不断简化与进化。而ksqlDB的出现,为我们带来了一个全新的视角 - 它不仅仅是一个流处理引擎,更是重新定义了我们与实时数据交互的方式。 让我们重新认识流处…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测

uniapp 中配置 配置manifest 文档&#xff1a;manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号&#xff1a;4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态

前言 在人工智能技术飞速发展的今天&#xff0c;深度学习与大模型技术已成为推动行业变革的核心驱动力&#xff0c;而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心&#xff0c;系统性地呈现了两部深度技术著作的精华&#xff1a;…...