源码分析Mybatis拦截器(Interceptor)拦截saveBatch()获取不到实体id的原因

news2024/11/14 20:40:25

1.背景

由于业务需求想在Mybatis拦截器层面获取insert后实体id去做相关业务。但是发现执行saveBatch()方法时,获取参数实体的时候,拿不到自增id。但是save()方法可以。

save方法之所以可以是因为:

MybatisPlus的BaseMapper执行insert方法后实体带自增id的原因是,在数据库表中设置了主键自增属性。当插入一条新的记录时,数据库会自动为这条记录生成一个唯一的自增id,并将这个id赋值给实体类中的主键属性。因此,当你查询这条记录时,实体类中的主键属性就会带有自增id。

save()和saveBatch()的基本原理:

MybatisPlus是MyBatis的增强工具,它在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。在具体操作上,MybatisPlus提供了save()和saveBatch()两种方法用于数据的保存。

save()方法是通过调用BaseMapper封装的单条保存数据的insert()方法实现的。也就是说,当我们调用save()方法时,会直接将数据插入到数据库中。

而saveBatch()方法则是用于批量插入数据。在使用时,需要传入一个列表集合以及一个默认的批量插入数量(默认为1000)。在内部实现上,MybatisPlus会遍历这个列表集合,并依次将数据插入到数据库中。此外,需要注意的是,虽然saveBatch()方法可以实现批量插入,但根据实际测试和观察,批量插入的效率可能会受到一定影响。因此,在使用saveBatch()方法进行批量插入时,可能需要考虑优化方案以提高插入效率。

拦截器代码(简化版):


@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class TodoInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        Object parameter = args[1];

        // 调用原始方法
        Object result = invocation.proceed();

        if (parameter instanceof Enquiry) {
            Enquiry enquiry = (Enquiry) parameter;
        }


        return result;
    }

2.现象

我分别执行save和saveBatch方法,附带截图:

save():

saveBatch():

如图所示,saveBatch()方法的实体在拦截器里是获取不到自增id的。特别说明下,debug你会发现,MybatisPlus执行saveBatch()方法会遍历这个列表集合,并依次将数据插入到数据库中。因为拦截器会执行次数是和实体列表的数量是一致。

3.源码分析原因

第一步:

ServiceImpl类

    public boolean saveBatch(Collection<T> entityList, int batchSize) {
        String sqlStatement = this.getSqlStatement(SqlMethod.INSERT_ONE);
        return this.executeBatch(entityList, batchSize, (sqlSession, entity) -> {

            //这里是拼装SQL,即每个实体类都是一个insert into 的sql
            sqlSession.insert(sqlStatement, entity);
        });
    }

第二步:

SqlHelper类
public static <E> boolean executeBatch(Class<?> entityClass, Log log, Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
        Assert.isFalse(batchSize < 1, "batchSize must not be less than one", new Object[0]);
        return !CollectionUtils.isEmpty(list) && executeBatch(entityClass, log, (sqlSession) -> {
            int size = list.size();
            int idxLimit = Math.min(batchSize, size);
            int i = 1;
            
            //从这里for可以看出,每实体就是一个insert语句
            for(Iterator var7 = list.iterator(); var7.hasNext(); ++i) {
                E element = var7.next();

                //这里就是与数据库配置,执行了sql,同时拦截器也是在这个方法里面执行的
                consumer.accept(sqlSession, element);
                if (i == idxLimit) {

                    //这里很重要,刷新缓存,执行这里后可以拿到插入后的id。
                    //所以,大家想想,上面accept方法拿不到id的原因就是如此了。
                    sqlSession.flushStatements();
                    idxLimit = Math.min(idxLimit + batchSize, size);
                }
            }

        });
    }

展示debug结果:

大家可以看到,执行了sqlSession.flushStatements()方法后就出现了id。所以也是大家发现在controller层,service层等执行saveBatch方法能拿到id,在拦截器却不可以,原因就在这里

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1228435.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在虚拟机的Ubuntu22.04中设置静态IP地址

为了让Linux系统的IP地址在重新启动电脑之后IP地址不进行变更&#xff0c;所以将其IP地址设置为静态IP地址。 查看虚拟机中虚拟网络编辑器获取当前的子网IP端 修改文件/etc/netplan/00-installer-config.yaml文件&#xff0c;打开你会看到以下内容 # This is the network conf…

java拼图小游戏

第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 然后是创建类 创建一个代码类 和一个运行类 代码如下&#xff1a; package heima;import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import jav…

深入理解注意力机制(下)——缩放点积注意力及示例

一、介绍 在这篇文章中&#xff0c;我们将重点介绍 Transformer 背后的 Scaled Dot-Product Attention&#xff0c;并详细解释其计算逻辑和设计原理。 在文章的最后&#xff0c;我们还会提供一个Attention的使用示例&#xff0c;希望读者看完后能够对Attention有更全面的了解。…

将word中的表格无变形的弄进excel中

在上篇文章中记录了将excel表拷贝到word中来&#xff1a; 记录将excel表无变形的弄进word里面来-CSDN博客 本篇记录&#xff1a;将word中的表格无变形的弄进excel中。 1.按F12&#xff0c;“另存为...”&#xff0c;保存类型&#xff1a;“单个文件页面”&#xff0c;保存。…

Java读写Jar

Java提供了读写jar的类库Java.util.jar&#xff0c;Java获取解析jar包的工具类如下&#xff1a; import java.io.File; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.util.Enumeration; import java.util.HashMap; import …

【C++入门到精通】新的类功能 | 可变参数模板 C++11 [ C++入门 ]

阅读导航 引言一、新的类功能1. 默认成员函数2. 类成员变量初始化3. 强制生成默认函数的关键字default4. 禁止生成默认函数的关键字delete5. override 和 final&#xff08;1&#xff09;override&#xff08;2&#xff09;final 二、可变参数模板递归函数方式展开参数包逗号表…

C# Winform围棋棋盘

C# Winform简单的围棋棋盘vs2008winform小游戏C#vs2010winform棋盘C#窗体小游戏 这是一个简单的围棋棋盘小游戏&#xff0c;使用C# Winform编写棋盘界面&#xff0c;玩家可以在空白的交叉点上下棋子 项目获取&#xff1a; 项目获取&#xff1a;typora: typora/img (gitee.co…

支付宝沙箱支付

支付宝沙箱支付 支付宝沙箱&#xff08;Alipay Sandbox&#xff09;是支付宝提供的一个模拟环境&#xff0c;用于开发者在不影响真实交易的情况下进行支付宝相关功能的测试和调试。在软件开发中&#xff0c;沙箱环境通常指的是一个隔离的测试环境&#xff0c;可以模拟真实环境…

【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…

Python 自动化(十八)admin后台管理

admin后台管理 什么是admin后台管理 django提供了比较完善的后台数据库的接口&#xff0c;可供开发过程中调用和测试使用 django会搜集所有已注册的模型类&#xff0c;为这些模型类提供数据管理界面&#xff0c;供开发使用 admin配置步骤 创建后台管理账号 该账号为管理后…

2023年中职“网络安全“—Web 渗透测试①

2023年中职"网络安全"—Web 渗透测试① Web 渗透测试任务环境说明&#xff1a;1.访问地址http://靶机IP/task1&#xff0c;分析页面内容&#xff0c;获取flag值&#xff0c;Flag格式为flag{xxx}&#xff1b;2.访问地址http://靶机IP/task2&#xff0c;访问登录页面。…

【每日一题】三个无重叠子数组的最大和

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;滑动窗口 写在最后 Tag 【滑动窗口】【数组】【2023-11-19】 题目来源 689. 三个无重叠子数组的最大和 题目解读 解题思路 方法一&#xff1a;滑动窗口 单个子数组的最大和 我们先来考虑一个长度为 k 的子数组的最…

【开源】基于Vue.js的创意工坊双创管理系统

项目编号&#xff1a; S 049 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S049&#xff0c;文末获取源码。} 项目编号&#xff1a;S049&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 管理员端2.2 Web 端2.3 移动端 三、…

leetcode算法之分治-快排

目录 1.颜色分类2.排序数组3.数组中的第k个最大元素4.最小的k个数 1.颜色分类 颜色分类 class Solution { public:void sortColors(vector<int>& nums) {int n nums.size();int left -1,rightn,i0;while(i<right){if(nums[i] 0) swap(nums[left],nums[i]);e…

力扣 字母异位词分组 哈表 集合

&#x1f468;‍&#x1f3eb; 力扣 字母异位词分组 ⭐ 思路 由于互为字母异位词的两个字符串包含的字母相同&#xff0c;因此对两个字符串分别进行排序之后得到的字符串一定是相同的&#xff0c;故可以将排序之后的字符串作为哈希表的键。 &#x1f351; AC code class Solut…

设计模式-行为型模式-策略模式

一、什么是策略模式 策略模式是一种行为设计模式&#xff0c;它允许在运行时选择算法或行为&#xff0c;并将其封装成独立的对象&#xff0c;使得这些算法或行为可以相互替换&#xff0c;而不影响使用它们的客户端。&#xff08;ChatGPT生成&#xff09; 主要组成部分&#xff…

一款实用的.NET Core加密解密工具类库

前言 在我们日常开发工作中&#xff0c;为了数据安全问题对数据加密、解密是必不可少的。加密方式有很多种如常见的AES&#xff0c;RSA&#xff0c;MD5&#xff0c;SAH1&#xff0c;SAH256&#xff0c;DES等&#xff0c;这时候假如我们有一个封装的对应加密解密工具类可以直接…

【STL】:反向迭代器

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关反向迭代器的模拟实现&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通…

【kafka】使用docker启动kafka

1.环境准备 docker拉取zookeeper镜像 docker pull zookeeper:3.4.14 创建zookeeper容器&#xff0c;默认端口号为2181 docker run -d --name zookeeper -p 2181:2181 zookeeper:3.4.14 拉取kafka镜像 docker pull wurstmeister/kafka:2.12-2.3.1 创键kafka容器&#xff…

c语言-输入输出详解

文章目录 格式化输入输出占位符printfscanf 字符串输入输出puts&#xff08;&#xff09;gets&#xff08;&#xff09; 字符输入输出putchar&#xff08;&#xff09;getchar&#xff08;&#xff09; 区别 格式化输入输出 输入输出的库函数的头文件&#xff1a; #include<…