MybatisPlus源码解析5:insert如何生成主键

【问题集锦 -02】MyBatis-Plus多节点多线程批量插入(insertBatch) 唯一主键ID冲突(Duplicate entry ‘xxxx‘ for key ‘PRIMARY‘) MyBatis-Plus 版本 3.5.1,使用Springboot搭建的项目工程。使用MyBatis-Plus中自动生成ID主键,类型为:ASSIGN_ID (使用的雪花算法生成唯一主键ID)。部署环境:采用一台服务器Docker多节点,多线程批量插入数据。 阅读详情

MybatisPlus源码解析5:insert如何生成主键

1. 问题

有没有想过一个问题,平时在保存数据的时候,没有指定id,但是在插入的Sql中有id,Mybatis-Plus是如何帮我们生成的ID

2. ID生成器的执行流程

ID生成器的执行流程与MetaObjectHandler的执行流程一模一样,都是在生成StatementHandler的时候对参数进行处理,因为两者的功能都是对参数进行填充。

MeataObjectHandler执行流程可参考:MybatisPlus源码解析3:元数据处理器-MetaObjectHandler

private void process(Object parameter) {
    if (parameter != null) {
        TableInfo tableInfo = null;
        Object entity = parameter;
        if (parameter instanceof Map) {
            // 处理单参数使用注解标记的时候,尝试提取et来获取实体参数
            Map<?, ?> map = (Map<?, ?>) parameter;
            if (map.containsKey(Constants.ENTITY)) {
                Object et = map.get(Constants.ENTITY);
                if (et != null) {
                    entity = et;
                    tableInfo = TableInfoHelper.getTableInfo(entity.getClass());
                }
            }
        } else {
            tableInfo = TableInfoHelper.getTableInfo(parameter.getClass());
        }
        if (tableInfo != null) {
            //到这里就应该转换到实体参数对象了,因为填充和ID处理都是针对实体对象处理的,不用传递原参数对象下去.
            MetaObject metaObject = this.configuration.newMetaObject(entity);
            if (SqlCommandType.INSERT == this.sqlCommandType) {
                populateKeys(tableInfo, metaObject, entity);
                insertFill(metaObject, tableInfo);
            } else {
                updateFill(metaObject, tableInfo);
            }
        }
    }
}

可以看到,populateKeys(tableInfo, metaObject, entity)是对主键进行填充,而insertFill和updateFill是对保存的数据属性进行填充

3.id生成与填充

protected void populateKeys(TableInfo tableInfo, MetaObject metaObject, Object entity) {
    final IdType idType = tableInfo.getIdType();
    final String keyProperty = tableInfo.getKeyProperty();
    if (StringUtils.isNotBlank(keyProperty) && null != idType && idType.getKey() >= 3) {
        final IdentifierGenerator identifierGenerator = GlobalConfigUtils.getGlobalConfig(this.configuration).getIdentifierGenerator();
        Object idValue = metaObject.getValue(keyProperty);
        if (identifierGenerator.assignId(idValue)) {
            if (idType.getKey() == IdType.ASSIGN_ID.getKey()) {
                Class<?> keyType = tableInfo.getKeyType();
                if (Number.class.isAssignableFrom(keyType)) {
                    Number id = identifierGenerator.nextId(entity);
                    if (keyType == id.getClass()) {
                        metaObject.setValue(keyProperty, id);
                    } else if (Integer.class == keyType) {
                        metaObject.setValue(keyProperty, id.intValue());
                    } else if (Long.class == keyType) {
                        metaObject.setValue(keyProperty, id.longValue());
                    } else if (BigDecimal.class.isAssignableFrom(keyType)) {
                        metaObject.setValue(keyProperty, new BigDecimal(id.longValue()));
                    } else if (BigInteger.class.isAssignableFrom(keyType)) {
                        metaObject.setValue(keyProperty, new BigInteger(id.toString()));
                    } else {
                        throw new MybatisPlusException("Key type '" + keyType + "' not supported");
                    }
                } else if (String.class.isAssignableFrom(keyType)) {
                    metaObject.setValue(keyProperty, identifierGenerator.nextId(entity).toString());
                } else {
                    metaObject.setValue(keyProperty, identifierGenerator.nextId(entity));
                }
            } else if (idType.getKey() == IdType.ASSIGN_UUID.getKey()) {
                metaObject.setValue(keyProperty, identifierGenerator.nextUUID(entity));
            }
        }
    }
}
  1. 从全局配置GlobalConfig中获取ID生成器,如果没有配置,mp默认的是DefaultIdentifierGenerator生成器
  2. 获取到当前的主键的值,判断是否为空,如果为空就去填充。不为空就什么也不做,使用参数本身的主键值
  3. 判断id的类型为ASSIGN_ID(Number类型)还是ASSIGN_UUID(String类型),这里可以通过@TableId#type去指定
    3.1. 如果是ASSIGN_ID,就调用identifierGenerator#nextId方法生成主键值
    3.2. 如果是ASSIGN_UUID,就调用identifierGenerator#nextUUID生成主键值
  4. 通过metaObject将主键值到参数对象里面 metaObject.setValue

4.默认和指定idType

idType是在启动流程,初始化tableInfo的时候确定的。
启动流程可参考:MybatisPlus源码解析2:mybatis-plus启动流程之Sql注入器-SqlInjector

private static void initTableIdWithAnnotation(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo, Field field, TableId tableId) {
    boolean underCamel = tableInfo.isUnderCamel();
     final String property = field.getName();
     if (field.getAnnotation(TableField.class) != null) {
         logger.warn(String.format("This \"%s\" is the table primary key by @TableId annotation in Class: \"%s\",So @TableField annotation will not work!",
             property, tableInfo.getEntityType().getName()));
     }
     /* 主键策略( 注解 > 全局 ) */
     // 设置 Sequence 其他策略无效
     if (IdType.NONE == tableId.type()) {
         tableInfo.setIdType(dbConfig.getIdType());
     } else {
         tableInfo.setIdType(tableId.type());
     }

     /* 字段 */
     String column = property;
     if (StringUtils.isNotBlank(tableId.value())) {
         column = tableId.value();
     } else {
         // 开启字段下划线申明
         if (underCamel) {
             column = StringUtils.camelToUnderline(column);
         }
         // 全局大写命名
         if (dbConfig.isCapitalMode()) {
             column = column.toUpperCase();
         }
     }
     final Class<?> keyType = tableInfo.getReflector().getGetterType(property);
     if (keyType.isPrimitive()) {
         logger.warn(String.format("This primary key of \"%s\" is primitive !不建议如此请使用包装类 in Class: \"%s\"",
             property, tableInfo.getEntityType().getName()));
     }
     if (StringUtils.isEmpty(tableId.value())) {
         String columnFormat = dbConfig.getColumnFormat();
         if (StringUtils.isNotBlank(columnFormat)) {
             column = String.format(columnFormat, column);
         }
     }
     tableInfo.setKeyRelated(checkRelated(underCamel, property, column))
         .setKeyColumn(column)
         .setKeyProperty(property)
         .setKeyType(keyType);
 }
  1. @TableId注解中的type默认为IdType.NONE
  2. 如果为IdType.NONE,那么就取全局配置中的dbConfig.getIdType(),而全局配置默认为IdType.ASSIGN_ID。所以就是默认为IdType.ASSIGN_ID
  3. 如果不为IdType.NONE,就取@TableId中指定的type
Mybatis-plus两种批量插入方法比较(带源码) Mybatis-plus两种批量插入方法比较1 SQL注入器方式1.1 SqlInjector 注入器类1.2 MyBatisPlusConfig 配置类1.3 Mapper基础类1.4 UserMapper 继承MyBaseMapper类2 IService方式2.1 BatchHandlerMapper 接口2.2 DeptMapper 接口2.3 BatchHandlerMapperImpl类3 测试4 测试结果4.1 一万条数据4.2 一百万条数据5 原因5.1 IService源码5.2 SQL注 阅读详情

相关推荐

【MyBatis-Plus】之批量插入

一、应用情景介绍 在实际的项目开发过程中,常常遇到批量保存数据的场景,当数据量比较少,比如只有几条数据的情况下,我们可以使用 for 循环来 insert 数据,但如果数据量比较多的情况下就不行,特别是并发的情况下,因为这样会增加数据库的负担。 我们通过查看 mybatis-plus 源码发现,mybatis-plus 的 IService API 接口提供了批量插入的接口: public interface IService<T> { ...... /** * 插入

王廷云的博客 1万+

深入了解:MybatisPlus中插入数据获取主键值

MybatisPlus是一个基于MyBatis的增强框架,提供了许多方便实用的功能。在插入数据时,我们常常需要获取插入后生成的主键值。本文将介绍在MybatisPlus中如何获取插入数据的主键值。通过本文的介绍,我们了解了在MybatisPlus中如何获取插入数据的主键值。可以根据实际需求选择合适的方法来获取插入数据后生成的主键值。在使用过程中,需要注意数据库表的主键属性设置和数据库的支持情况,以保证获取主键值的准确性。希望本文对大家在使用MybatisPlus插入数据并获取主键值时有所帮助。

牛肉胡辣汤 2764

MybatisPlus BaseMapper 实现对数据库增删改查源码解析

MybatisPlus 是一款在 Mybatis 基础上进行的增强 orm 框架,可以实现不写 sql 就完成数据库相关的操作。接下来就对其源码一探究竟,看看他到底是如何实现的。

m0_71777195的博客 2678

mybatis实战:四、insert 用法(普通插入、返回主键自增的值)

database Id :如果配置了 databaseidProvider会加载所有的不带 databaseId 的或匹配当前 databaseId 的语句 如果同时存在带databaseId 和不带 databaseid 的语句,后者会被忽略.parameterType :即将传入的语句参数的完全限定类名或别名 这个属性是可选的,因为 MyBatis 可以推断出传入语句的具体参数,因此不建议配置该属性。序指定数据库的列,这里列的值会和 keyProperty 配置的属性一一对应。

H215919719的博客 9180

MybatisPlus + ShardingSphere JDBC批量插入不返回主键?5.2.1版本终极解决方案

本文深度解析MybatisPlus与ShardingSphere JDBC在批量插入时主键丢失的问题,提供5.2.1版本的终极解决方案。通过技术原理剖析、实战代码示例和性能优化建议,帮助开发者解决`saveBatch`方法不返回主键的常见难题,提升分库分表场景下的数据操作效率。

weixin_29280219的博客 575

MybatisPlus简介——第一个MybatisPlus程序(基于SpringBoot工程)

支持全局通用方法注入( Write once, use anywhere )

2401_88972316的博客 1162

MybatisPlus主键生成策略与自动填充

snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。创建时间、修改时间,这些操作一般都是自动化完成的,不希望手动更新。在实体类对象中配置,前提是数据库表中也是设置自增的。数据库表通常是不能够修改的,在代码中使用自动填充。

weixin_60719453的博客 2606

MybatisPlus saveOrUpdate 实战避坑指南:从主键困惑到条件构造器的正确姿势

本文深入解析MybatisPlus的saveOrUpdate方法在实际项目中的使用技巧与常见陷阱。从主键标注、自增主键处理到条件构造器的正确使用,详细介绍了如何避免数据重复插入和更新失败的问题。特别针对MySQL的ON DUPLICATE KEY UPDATE语法进行了性能优化分析,并提供了多字段唯一约束和批量操作的最佳实践方案。

weixin_30892889的博客 576

mybatisplus自增主键很大问题排错

一天上午,小明突然叫我说数据库数据很奇怪,我看了下的确好奇怪 为什么自增id字段突然变得怎么大了,后面我比对下其他的库表,有点自增id是ok,有的也出现上述的情况,我一开始就纳闷了,然后开启数据库的打印语句,发现入库语句如下: JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@21f78019] will be managed by Spring ==> Preparing: INSERT INTO user ( i

得救之道就在其中 8191

2023年第二十届五一数学建模竞赛C题:“双碳”目标下低碳建筑研究-思路详解与代码答案

2023年第二十届五一数学建模竞赛C题:“双碳”目标下低碳建筑研究-思路详解与代码答案

lichensun的博客 1万+

MATLAB下pdf文件操作读取示例

当遇到一些需要大量数据的项目,数据的读取与储存显得尤为重要。怎样把数据从其他格式的文件中读取,并运用到程序中是很多时候我们要解决的问题。对于平常的.txt,和.xlsx文件,MATLAB有对应的函数帮助读取,但是遇到pdf文件时MATLAB很难读取内容。本文以一个操作实例提供了一个从pdf文件中读取数据的方法。

UESTC 五高考3模拟的博客 6557

myBatisPlus总结

mybatisPlus的一些总结

weixin_68010168的博客 2129

昇腾CANN实战:如何用DVPP+AIPP实现32路视频流毫秒级预处理(附性能对比)

本文深入探讨了昇腾CANN架构中DVPP和AIPP模块在32路视频流毫秒级预处理中的硬件加速技术。通过异构计算架构的优化,实现了从传统CPU方案的40.7毫秒到CANN方案3.4毫秒的显著性能提升,特别适用于智能安防领域的实时视频分析需求。文章详细解析了DVPP多通道并行设计和AIPP模型级预处理融合的技术细节,并提供了性能对比数据与实战调优经验。

alice7model的博客 918

全网最强MyBatisPlus教程 | 万字长文爆肝MyBatisPlus

MyBatisPlus是基于MyBatis的增强工具,旨在简化开发和提高效率。文章介绍了基于SpringBoot整合MyBatisPlus的入门案例,包括创建数据库、配置依赖、编写实体类和Dao接口等步骤。MyBatisPlus通过继承BaseMapper接口,无需编写SQL即可实现标准CRUD操作,大幅简化开发流程。同时还介绍了MyBatisPlus的官方文档和定位,强调其作为MyBatis的增强工具而非替代品的角色。文中包含详细的操作步骤和配置示例,适合初学者快速上手使用MyBatisPlus。

qq_45832461的博客 2308

Ansys Lumerical 2023 R1.2新功能实战:薄膜铌酸锂调制器仿真全流程解析

本文详细解析了Ansys Lumerical 2023 R1.2在薄膜铌酸锂电光相位调制器仿真中的最新功能与应用。通过实战演示,展示了从电极配置、电场计算到模式分析的全流程,重点介绍了各向异性介电常数支持和多物理场耦合优化等关键技术,助力开发者高效设计高性能光通信器件。

weixin_28454475的博客 1204

HAMi 核心模块与架构设计

HAMi 的架构设计是围绕 Kubernetes 生态系统构建的,通过扩展 Kubernetes 的调度能力和设备管理能力,为用户提供了高效、灵活的异构设备虚拟化和管理解决方案。

北斗云的博客 2552

数据库不设置主键自增时,mybatisPlus插入数据不能插入主键

今天写项目调用insert方法的时候,生成的sql不带主键,数据库不能修改,最后查看源码发现mybatisPlus的主键策略默认是NONE 下面普及一下mybatisPlus的主键策略 AUTO,//数据库自增 依赖数据库 NONE,// 表示该类型未甚至主键类型 (如果没有主键策略)默认根据雪花算法生成 INPUT,//用户输入ID(该类型可以通过自己注册填充插件进行填充) //下面这三种类型,只有当插入对象id为空时 才会自动填充。 ID_WORKER,//全局唯一(idWorker)数值类型 UUI

s1070838653的博客 5493

SD-WAN组网案例——数据中心

SD-WAN组网案例——数据中心

2301_78457663的博客 705

MyBatisPlus——学习笔记

MyBatisPlus学习笔记

qq_45791526的博客 1391

web逆向伪瑞数案例:宝武资源有限公司(面向对象补环境)

声明:该文章为学习使用,严禁用于商业用途和非法用途,违者后果自负,由此产生的一切后果均与作者无关前言:之所以称伪瑞数案例,是因为该网站,无论是补环境的方法、还是环境都和瑞数差不多,因为第一次遇到这种网站,不确定是不是瑞数的一种,所以这里称伪瑞数,有知道的道友,可以评论区评论下,共同进步。,这里就不做多介绍了1.瑞数中的是t​s,而该网站是_ss。2.外链js代码不能格式化,否则补环境时会遇到一个超过数组长度的报错。3.call执行后的虚拟文件中有超多的debugger。

老衲爱洗头的博客 2533

弥散圆以及最大弥散圆

1弥散圆的形成? 原本景物中的一点应该经过透镜本应该也是一点才对。但是因为离焦,球差的存在,最终成像会投影成一个光斑圆圈。越小越清晰,越大就互相干涉变得越模糊。 同时人们规定二零最大弥散圆,就是人眼能够感受清晰模糊的一个边界,直径大于它,感受到模糊;直径小于它,感受不到模糊。 下面分别是离焦(左),球差(右)。 2弥散圆大小怎么计算呢? ,f为焦距;<1> ,D为光圈有效孔径;<2> F=f/D; <3> 3条公式合并可得出: ...

camerall 3114

【MybatisPlus】最全面的MybatisPlus通关教程_mybatisplus 菜鸟教程

数据库插入的id的默认值为:全局的唯一id。

2401_84166147的博客 862

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

mybatisplus查询今天的数据_MybatisPlus(CRUD)

插入功能//测试插入@Testpublic void testInsert(){ User user = new User(); user.setName("ironman"); user.setAge(3); user.setEmail("123456@qq.com"); System.out.println(user); System.out.pr...

weixin_39675178的博客 1311

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

MybatisPlus学习总结

简介 | MyBatis-PlusMyBatis Plus是一个基于MyBatis的增强工具,它简化了MyBatis的使用,提供了一系列的增强功能,使开发更加方便快捷。无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求支持 Lambda 形式调用。

梦想也许遥不可及,但重要的是追梦的过程,用博客记录自己的成长,记录自己一步一步向上攀登的印记 1417

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

MyBatis-Plus 主键生成策略

MyBatis-Plus 主键生成策略 接上一篇博客:快速上手 MyBatis-Plus 开发 在测试类中执行 Insert 操作,向数据表中插入记录: //测试插入操作 @Test public void testInsert(){ User user = new User(); user.setName("Cloud"); user.setAge(3); user.setEmail("12265663@qq.com"); //MP自动生成id int res =

qq_41775769的博客 1743

Mybatisplus学习笔记

wrapper”(条件包装器)是一个用于构建 SQL 查询条件的对象。它通过提供一组方法,允许您动态地构建复杂的查询条件。MyBatis Plus 的 Wrapper 接口是一个通用的查询条件包装器接口,用于构建查询时的条件约束。它定义了一系列的方法,例如eqnelikein等,用于指定字段的条件和操作符。Wrapper : 条件构造抽象类,最顶端父类AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件QueryWrapper : 查询条件封装。

dogofjiaran的博客 997
上一篇: Mybatis & Mybatis Plus源码解析
下一篇: MybatisPlus源码解析3:元数据处理器-MetaObjectHandler
hao9e
博客等级 码龄7年 189粉丝 51原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值