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批量插入
本博客借鉴网上很多大佬的答案,东拼西凑,最终在项目中完成批量插入,仅供参考~~~ 1. 自定义SQL注入器 新建一个名为EasySqlInjector的类,继承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 是一款低功耗单声道音频编解码器,具有全差分输出,支持在全差分配置下可编程模拟输入。可pin to pin兼容ES8311。 录音路径包含一个全差分输入,低噪声可编程增益放大器和自动增益控制(ALC)。在录音过程中,通过内…...
通用AT指令
1、查询SIM卡状态 ATCPIN?2、查询信号强度 ATCSQ //99,99 表示无信号3、查询IMEI ATCGSN4、查询4G/5G模式 ATCOPS? //7表示在4G模式,13表示在5G模式5、设置接入点 ATCGDCONT1,"IP","uninet" //联通 ATCGDCONT1,"IP","…...
二进制狼群算法
本文所涉及所有资源均在 传知代码平台 可获取。 目录 一、背景及意义介绍 背景 意义...
STL——list的介绍和使用
前言 本篇博客我们继续来介绍STL的内容,这次我们要介绍的是list这个容器,可以简单地理解为顺序表,当然和我们之前学过顺序表还是有区别的,具体内容大家可以继续往下阅读,下面进入正文。 1. list简介 1.list是一种可…...
二百七十六、ClickHouse——Hive和ClickHouse非常不同的DWS指标数据SQL语句
一、目的 在完成数据之后对业务指标进行分析,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格式并存在时区差异时,可通过设置字段格式如yyyy-MM-dd HH:mm:ss并指定时区为GMT8来解决。存储Date类型数据时,可以使用JSON库如json-lib, fastjson, Jackson或gson进行…...
mathorcup2024台风 我all in ai
三个问题,力大砖飞。 不建物理模型,直接all in好吧 第一个故意无监督 第二个LSTMCNN注意力,刚好时间空间 第三个在第二个上加了个transfomer ,然后LSTM变双向,增加层数(基线模型选的经验公式,少…...
android 10 后台启动activity
摘要:Android 10(API 级别 29)及更高版本会限制应用何时可以启动 activity 背景。这些限制有助于最大限度地减少对用户的干扰, 让用户能够更好地控制其屏幕上显示的内容。本文以此为出发点,基于展锐平台对系统代码进行…...
文案创作新思路:Python与文心一言API的完美结合
在这个信息爆炸的时代,内容创作似乎成了一项需要魔法才能完成的任务。不过,别担心!今天,我们将向你介绍一种新的“魔法”工具——百度文心一言 API。这款大语言模型不仅能与人对话互动,还能高效便捷地协助你获取创意灵…...
CentOS 7 上安装 MySQL 8.0 教程
🌟 你好 欢迎来到我的技术小宇宙!🌌 这里不仅是我记录技术点滴的后花园,也是我分享学习心得和项目经验的乐园。📚 无论你是技术小白还是资深大牛,这里总有一些内容能触动你的好奇心。🔍 &#x…...
Chromium HTML5 新的 Input 类型url对应c++
一、Input 类型: url url 类型用于应该包含 URL 地址的输入域。 在提交表单时,会自动验证 url 域的值。 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>test</title> </head> <body&g…...
java多线程编程(二)一一>线程安全问题, 单例模式, 解决程线程安全问题的措施
引言: 如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的 线程安全问题的原因: 一.操作系统的随机调度 : 二.多个线程修改同一个变量: 三.修改操作不是…...
Leetcode 213. 打家劫舍 II 动态规划
原题链接: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]);// 如果偷了第一家,就不能偷最后一家int dp[n - 1];dp[0] …...
就业市场变革:AI时代,我们将如何评估人才?
内容概要 在这个充满变革的时代,就业市场正被人工智能(AI)技术深刻改变。随着技术的进步,传统的人才评估方式逐渐显示出其局限性。例如,过去依赖于纸质简历和面试评估的方式在快速变化的环境中难以准确识别真实的人才…...
富格林:安全操作方式稳健出金
富格林认为,黄金一直是吸引投资者关注的投资产品之一,投资者不断踏入黄金投资交易市场。很多投资者都以为现货黄金投资是很容易实现出金获得丰厚利润,但是面对复杂的交易市场,不仅不能轻易实现安全获利出金,甚至可能还…...
早点包子店点餐的软件下载和点餐操作教程 佳易王餐饮点餐管理系统操作方法
一、概述 【软件试用版资源文件可以点文章最后卡片了解】 早点包子店点餐的软件下载和点餐操作教程 适合于早点早餐餐饮行业的软件,实现早点点餐,收银会员管理,库存统计,销售统计等一体化操作。 点餐的时候可以用手触摸点&…...
uniapp一键打包
1.先安装python环境, 2.复制这几个文件到uniapp项目里面 3.修改自己证书路径,配置文件路径什么的 4.在文件夹页面双击buildController.py或者cmd直接输入buildController.py 5.python报错,哪个依赖缺少安装哪个依赖 6.执行不动的话&…...
什么是ksqlDB?流处理世界里的新范式
在大数据技术快速迭代的今天,我们见证了数据处理范式的不断演进。从批处理到流处理,从复杂的编程框架到声明式API,技术在不断简化与进化。而ksqlDB的出现,为我们带来了一个全新的视角 - 它不仅仅是一个流处理引擎,更是重新定义了我们与实时数据交互的方式。 让我们重新认识流处…...
Sanic请求对象解析:全方位数据访问与处理终极指南
Sanic请求对象解析:全方位数据访问与处理终极指南 【免费下载链接】sanic Accelerate your web app development | Build fast. Run fast. 项目地址: https://gitcode.com/gh_mirrors/sa/sanic Sanic作为一款高性能的Python Web框架,以"Bui…...
Sherlock AI Plugin:自动化探测项目中AI集成的安全审计工具
1. 项目概述:一个能“嗅探”AI插件的侦探工具 如果你和我一样,在日常开发或者安全审计中,经常需要快速了解一个项目里集成了哪些AI能力,那你肯定遇到过这样的麻烦:你得手动去翻看代码库的配置文件、依赖声明࿰…...
TypeScript 对列,实现消息队列(FIFO显示+定时清理)
使用对列实现消息接收显示与清除, 根据消息的【显示时间】来清除,显示超过 10 秒的自动清理,未显示、显示不足 10 秒的都保留线程安全 Queue/*** 纯先进先出(FIFO)队列独立实现* 支持:入队、出队、查看队头…...
MetaGPT 论文精读:ICLR 2024 Oral,角色化流水线式多Agent协作
MetaGPT: Meta Programming for Multi-Agent Framework 论文:Yongchao et al., ICLR 2024 (Oral) 原文链接:https://openreview.net/forum?idVtmBAGCN7o 本文记录我的论文学习过程与核心理解 一、论文基础介绍 基本信息 项目信息论文MetaGPT: Meta Pr…...
洛谷P1074 [NOIP 2009 提高组] 靶形数独题解
什么 蓝题能用dfs做?!DFS大法好!这道题就是一道数独的加强版,还要算分数,数独问题就是DFS回溯加剪枝优化。填数独那就是dfs枚举填数情况(剪枝加回溯)解出来时 再去乘以图表就行了#include<bi…...
代码变现双擎:独立开发者的 Gumroad 与 CodeCanyon 掘金指南
除了接私活外包和打工,我们作为软件开发者,其实拥有天然的“造物”优势。我们在日常开发中顺手写出的各类脚本、UI 模板、系统插件,甚至是成型的完整小项目,都可以被打包成数字资产进行售卖。 今天,我们就来聊聊最适合…...
TFT Overlay:云顶之弈玩家的桌面战术助手,告别装备合成困扰
TFT Overlay:云顶之弈玩家的桌面战术助手,告别装备合成困扰 【免费下载链接】TFT-Overlay Overlay for Teamfight Tactics 项目地址: https://gitcode.com/gh_mirrors/tf/TFT-Overlay 你正在玩《云顶之弈》,面对8种基础装备和30多种合…...
内曲线液压马达可视化设计平台开发Matlab【附代码】
✅ 博主简介:擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导,毕业论文、期刊论文经验交流。 ✅ 如需沟通交流,扫描文章底部二维码。(1)导轨曲线库与性能分析模块的正向设计:基于等加速…...
025年-2026年AI智能体学术论文发表国家(地区)共现网络图
✓中国、美国的节点大小显著大于其他国家,说明两国在 AI智能体领域的论文发表量、研究活跃度处于全球顶尖水平,是该领域的核心创新主体。 ✓中国的节点略大于美国,反映出 2025-2026年中国在该领域的研究产出规模已处于全球领先地位。 ✓两国均…...
将 Claude Code 编程助手无缝对接至 Taotoken 平台以享受官方价折扣
将 Claude Code 编程助手无缝对接至 Taotoken 平台以享受官方价折扣 对于经常使用 Claude Code 作为编程助手的开发者而言,直接使用官方服务有时会面临成本与灵活性的考量。Taotoken 平台提供了 OpenAI 兼容的 HTTP API,同时也支持 Anthropic 兼容的通道…...
