Java + Spring Boot + Mybatis 插入数据后,获取自增 id 的方法
在 MyBatis 中使用 useGeneratedKeys="true"
获取新插入记录的自增 ID 值,可通过以下步骤实现:
1. 配置 Mapper XML
在插入语句的 <insert>
标签中设置:
xml
复制
下载
运行
<insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">INSERT INTO user(name, email)VALUES (#{name}, #{email}) </insert>
-
useGeneratedKeys="true"
:启用数据库生成的主键(如自增 ID)。 -
keyProperty="id"
:将生成的主键值赋给参数对象(如User
对象)的id
属性。
2. 定义实体类
确保实体类有对应的属性(与 keyProperty
一致):
java
复制
下载
public class User {private Long id; // 属性名必须与 keyProperty 匹配private String name;private String email;// Getter & Setter }
3. 调用 Mapper 方法
插入后,自动填充的 ID 会直接赋给传入的实体对象:
java
复制
下载
User newUser = new User(); newUser.setName("John"); newUser.setEmail("john@example.com");// 执行插入(返回的是影响行数,非 ID) int rows = userMapper.insertUser(newUser); // 插入后,自增 ID 已注入 newUser 的 id 属性 Long newId = newUser.getId(); // ✅ 直接获取 System.out.println("新记录的 ID:" + newId);
关键点说明
-
keyProperty
必须匹配实体属性名
如实体属性为userId
,则需配置keyProperty="userId"
。 -
支持批量插入(MyBatis 3.3.1+)
配置keyProperty
为集合元素的属性:xml
复制
下载
运行
<insert id="insertUsers" useGeneratedKeys="true" keyProperty="id">INSERT INTO user(name) VALUES <foreach collection="list" item="user" separator=",">(#{user.name})</foreach> </insert>
调用后,每个对象的
id
都会被赋值:java
复制
下载
List<User> users = Arrays.asList(new User("A"), new User("B")); userMapper.insertUsers(users); users.forEach(u -> System.out.println(u.getId())); // 输出所有新 ID
-
数据库兼容性
-
MySQL/SQL Server:直接支持
useGeneratedKeys
。 -
Oracle:需用
<selectKey>
配合序列(非本方案范畴)。
-
常见问题
-
获取值为
null
?
检查keyProperty
是否与实体属性名一致,或数据库是否真的生成了自增 ID。 -
批量插入无效?
确保 MyBatis 版本 ≥ 3.3.1,且keyProperty
指向集合元素的属性(如id
)。
通过此方案,插入后无需额外查询,ID 值直接注入对象属性,高效简洁。
在 MyBatis 中,keyProperty
可以指定为参数对象中的任意属性路径(包括嵌套对象或 Map 的键值),不一定必须是主实体对象的属性。以下是几种灵活用法:
1. 指定参数对象的嵌套属性
若参数是一个包含 ID 容器的复合对象:
java
复制
下载
public class InsertParam {private User user;private Long generatedId; // 专门接收 ID 的属性// Getter & Setter }
Mapper XML 配置:
xml
复制
下载
运行
<insert id="insertUser" parameterType="InsertParam" useGeneratedKeys="true" keyProperty="generatedId">INSERT INTO user(name) VALUES (#{user.name}) </insert>
插入后获取:
java
复制
下载
InsertParam param = new InsertParam(); param.setUser(new User("Alice")); userMapper.insertUser(param);Long newId = param.getGeneratedId(); // ✅ 从专用属性获取
2. 使用 Map
参数接收
直接通过 Map 传递参数并接收 ID:
xml
复制
下载
运行
<insert id="insertUser" parameterType="map"useGeneratedKeys="true" keyProperty="resultId">INSERT INTO user(name) VALUES (#{name}) </insert>
Java 调用:
java
复制
下载
Map<String, Object> params = new HashMap<>(); params.put("name", "Bob");userMapper.insertUser(params);Long newId = (Long) params.get("resultId"); // ✅ 从 Map 获取
3. 多参数场景(结合 @Param
)
当方法有多个参数时,用 @Param
指定命名空间:
java
复制
下载
int insertUser(@Param("user") User user,@Param("idHolder") Map<String, Long> idHolder // 专门存 ID 的 Map );
Mapper XML 配置:
xml
复制
下载
运行
<insert id="insertUser" useGeneratedKeys="true" keyProperty="idHolder.id">INSERT INTO user(name) VALUES (#{user.name}) </insert>
插入后获取:
java
复制
下载
Map<String, Long> idHolder = new HashMap<>(); User user = new User("Charlie");userMapper.insertUser(user, idHolder);Long newId = idHolder.get("id"); // ✅ 从独立 Map 获取
关键规则
-
路径匹配原则
keyProperty
的值是 OGNL 表达式,需严格匹配参数对象的属性路径:-
单参数:直接写属性名(如
generatedId
) -
多参数:用
@Param
别名前缀(如idHolder.id
)
-
-
批量插入场景
批量操作时keyProperty
需指向集合元素的属性(不支持外部容器):xml
复制
下载
运行
<!-- 正确:ID 注入到每个元素的 id 属性 --> <insert id="batchInsert" useGeneratedKeys="true" keyProperty="id">INSERT INTO user(name) VALUES <foreach item="item" collection="list" separator=",">(#{item.name})</foreach> </insert>
-
常见问题
-
属性未注入? 检查
keyProperty
路径是否存在 setter 方法 -
返回
null
? 确保数据库自增 ID 已生效(如 MySQL 的AUTO_INCREMENT
)
-
使用建议
-
专用 ID 容器:推荐用独立
Map
或 DTO 属性接收 ID,避免污染实体对象 -
明确路径:多参数时用
@Param
定义清晰命名空间(如keyProperty="holder.id"
) -
事务安全:插入后立即从参数对象中获取 ID,确保在同一事务内
当 Mapper 方法有多个参数时,MyBatis 无法确定将生成的自增 ID 注入到哪个参数中。以下是详细解决方案:
错误原因分析
复制
下载
Cause: org.apache.ibatis.executor.ExecutorException: Could not determine which parameter to assign generated keys to. Note that when there are multiple parameters, 'keyProperty' must include the parameter name
-
当 Mapper 方法有多个参数时,必须使用 参数名前缀 明确指定注入位置
-
您当前配置的
keyProperty="generatedId"
缺少参数名前缀 -
MyBatis 找到的可用参数:
[generatedId, ckDetailId, param1, param2]
解决方案:添加参数名前缀
方法 1:使用 @Param
注解明确命名参数
java
复制
下载
// Mapper 接口方法 int insertRecord(@Param("data") Map<String, Object> data, // 数据参数@Param("idHolder") Map<String, Long> idHolder // 专门接收ID的参数 );
xml
复制
下载
运行
<!-- Mapper XML 配置 --> <insert id="insertRecord" useGeneratedKeys="true" keyProperty="idHolder.generatedId"> <!-- 添加参数名前缀 -->INSERT INTO your_table(...) VALUES (#{data.field1}, #{data.field2}) </insert>
方法 2:使用 MyBatis 默认参数名(不推荐)
xml
复制
下载
运行
<insert id="insertRecord" useGeneratedKeys="true" keyProperty="param2.generatedId"> <!-- 使用paramN格式 -->... </insert>
参数索引从1开始:
param1
=第一个参数,param2
=第二个参数
完整示例代码
1. Mapper 接口
java
复制
下载
public interface YourMapper {int insertRecord(@Param("detail") YourEntity entity, // 实体参数@Param("idHolder") Map<String, Long> holder // ID容器参数); }
2. Mapper XML
xml
复制
下载
运行
<insert id="insertRecord" useGeneratedKeys="true"keyProperty="idHolder.generatedId"> <!-- 关键:带前缀的keyProperty -->INSERT INTO your_table(name, ck_detail_id)VALUES (#{detail.name}, #{detail.ckDetailId}) </insert>
3. 调用代码
java
复制
下载
// 准备参数 YourEntity entity = new YourEntity("test", 1001); Map<String, Long> idHolder = new HashMap<>(); // 专门接收ID// 执行插入 mapper.insertRecord(entity, idHolder); // 获取自增ID (注意键名与XML中一致) Long newId = idHolder.get("generatedId"); System.out.println("Generated ID: " + newId);
关键注意事项
-
前缀必须匹配
@Param
值
keyProperty="idHolder.generatedId"
对应:-
idHolder
→@Param("idHolder")
-
generatedId
→ Map中的键名
-
-
Map 接收 vs 对象属性
xml
复制
下载
运行
<!-- 如果使用对象属性接收 --> keyProperty="detail.id" <!-- 注入到实体对象的id属性 --><!-- 如果使用Map接收 --> keyProperty="idHolder.generatedId" <!-- 注入到Map的generatedId键 -->
-
批量插入特殊处理
批量操作时仍需注入到集合元素内:xml
复制
下载
运行
<insert id="batchInsert" useGeneratedKeys="true" keyProperty="id">INSERT ... <!-- 无法注入到外部参数 --> </insert>
常见错误排查
错误现象 | 解决方案 |
---|---|
返回null | 检查数据库自增列是否生效 |
报Invalid bound statement | 检查keyProperty 前缀是否匹配@Param 值 |
批量插入ID未注入 | 确保keyProperty 指向集合元素的属性 |
Oracle数据库不生效 | 需使用<selectKey> 替代 |
建议:对多参数场景始终使用
@Param
+ 前缀的keyProperty
,避免依赖paramN
隐式命名
相关文章:
Java + Spring Boot + Mybatis 插入数据后,获取自增 id 的方法
在 MyBatis 中使用 useGeneratedKeys"true" 获取新插入记录的自增 ID 值,可通过以下步骤实现: 1. 配置 Mapper XML 在插入语句的 <insert> 标签中设置: xml 复制 下载 运行 <insert id"insertUser" para…...

【Linux应用】Linux系统日志上报服务,以及thttpd的配置、发送函数
【Linux应用】Linux系统日志上报服务,以及thttpd的配置、发送函数 文章目录 thttpd服务安装thttpd配置thttpd服务thttpd函数日志效果和文件附录:开发板快速上手:镜像烧录、串口shell、外设挂载、WiFi配置、SSH连接、文件交互(RADX…...
Nginx 事件驱动理解
在做埋点采集服务的过程中,主要依靠openresty加lua脚本来实现采集。高并发还是主要依靠nginx来实现。而其核心就是事件驱动/多路io复用(epoll机制),不同的linux服务器都有对应的实现方式。 而epoll机制就是,应用启动的…...

Jmeter(四) - 如何在jmeter中创建网络测试计划
1.简介 如何创建基本的 测试计划来测试网站。您将创建五个用户,这些用户将请求发送到JMeter网站上的两个页面。另外,您将告诉用户两次运行测试。 因此,请求总数为(5个用户)x(2个请求)xÿ…...
Amazon RDS on AWS Outposts:解锁本地化云数据库的混合云新体验
在混合云架构成为企业数字化转型标配的今天,如何在本地数据中心享受云数据库的强大能力,同时满足数据本地化、低延迟访问的严苛需求?Amazon RDS on AWS Outposts 给出了完美答案——将AWS完全托管的云数据库服务无缝延伸至您的机房࿰…...

2025年上海市“星光计划”第十一届职业院校技能大赛 网络安全赛项技能操作模块样题
2025年上海市“星光计划”第十一届职业院校技能大赛 网络安全赛项技能操作模块样题 (二)模块 A:安全事件响应、网络安全数据取证、应用安全、系统安全任务一:漏洞扫描与利用:任务二:Windows 操作系统渗透测试 :任务三&…...
jieba实现和用RNN实现中文分词的区别
Jieba 分词和基于 RNN 的分词在技术路线、实现机制、性能特点上有显著差异,以下是核心对比: 1. 技术路线对比 维度Jieba 分词RNN 神经网络分词范式传统 NLP(规则 统计)深度学习(端到端学习)核心依赖词典…...
android计算器代码
本次作业要求实现一个计算器应用的基础框架。以下是布局文件的核心代码: <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"andr…...
leetcode 386. 字典序排数 中等
给你一个整数 n ,按字典序返回范围 [1, n] 内所有整数。 你必须设计一个时间复杂度为 O(n) 且使用 O(1) 额外空间的算法。 示例 1: 输入:n 13 输出:[1,10,11,12,13,2,3,4,5,6,7,8,9]示例 2: 输入:n 2…...

Modbus转ETHERNET IP网关:快速冷却系统的智能化升级密钥
现代工业自动化系统中,无锡耐特森Modbus转Ethernet IP网关MCN-EN3001扮演着至关重要的角色。通过这一技术,传统的串行通讯协议Modbus得以在更高速、更稳定的以太网环境中运行,为快速冷却系统等关键设施的自动化控制提供了强有力的支撑。快速冷…...

Linux——TCP和UDP
一、TCP协议 1.特点 TCP提供的是面向连接、可靠的、字节流服务。 2.编程流程 (1)服务器端的编程流程 ①socket() 方法创建套接字 ②bind()方法指定套接字使用的IP地址和端口。 ③listen()方法用来创建监听队列。 ④accept()方法处理客户端的连接…...
比较数据迁移后MySQL数据库和PostgreSQL数据仓库中的表
设计一个MySQL数据库和PostgreSQL数据库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较两…...
云原生技术驱动 IT 架构现代化转型:企业实践与落地策略全解
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、背景:IT 架构演进的战略拐点 过去十年,企业 IT 架构经历了从传统集中式架构到分布式架构的转型。进入云计算…...

Android Settings 数据库生成、监听与默认值配置
一、Settings 数据库生成机制 传统数据库生成(Android 6.0 前) 路径:/data/data/com.android.providers.settings/databases/settings.db创建流程: SQL 脚本初始化:通过 sqlite 工具创建数据库文件…...

SeaweedFS S3 Spring Boot Starter
SeaweedFS S3 Spring Boot Starter 源码特性环境要求快速开始1. 添加依赖2. 配置文件3. 使用方式方式一:注入服务类方式二:使用工具类 API 文档SeaweedFsS3Service 主要方法SeaweedFsS3Util 工具类方法 配置参数运行测试构建项目注意事项集成应用更多项目…...
Monorepo架构: 项目管理模式对比与考量
关于 monorepo 相关概念及项目管理模式 在软件开发中,尤其是前端项目,我们会涉及到不同的项目管理模式,这里先介绍几个重要的概念“monorepo”是当前较为热门的一种项目管理方式,虽然很多人可能听说过,但可能在实际项…...

智慧城市项目总体建设方案(Word700页+)
1 背景、现状和必要性 1.1 背景 1.1.1 立项背景情况 1.1.2 立项依据 1.2 现状 1.2.1 党建体系运行现状 1.2.2 政务体系运行现状 1.2.3 社会治理运行现状 1.2.4 安全监管体系现状 1.2.5 环保体系运行现状 1.2.6 城建体系运行现状 1.2.7 社区体系运行现状 1.2.8 园区…...

详解ZYNQ中的 RC 和 EP
详解ZYNQ中的 RC 和 EP 一、ZYNQ FPGA 开发板基础( ZC706 ) 1. 核心特点 双核大脑 灵活积木: ZC706 集成了 ARM Cortex-A9 双核处理器(相当于电脑 CPU)和 FPGA 可编程逻辑单元(相当于可自定义的硬件积木…...
CSP信奥赛C++常用系统函数汇总
# CSP信奥赛C常用系统函数汇总## 一、输入输出函数### 1. cin / cout(<iostream>) cpp int x; cin >> x; // 输入 cout << x << endl;// 输出 优化:ios::sync_with_stdio(false); 可提升速度 2. scanf() /…...
Qt Quick Dialogs模块功能及架构
Qt Quick Dialogs 是 Qt Quick 的一个附加模块,提供了一套用于创建和使用系统对话框的 QML 类型。在 Qt 6.0 中,这个模块经过了重构和增强。 一、主要功能和特点 1. 对话框类型 Qt Quick Dialogs 在 Qt 6.0 中提供了以下标准对话框类型: …...
Unity基础-Mathf相关
Unity基础-Mathf相关 一、Mathf数学工具 概述 Mathf是Unity中封装好用于数学计算的工具结构体,提供了丰富的数学计算方法,特别适用于游戏开发场景。它是Unity开发中最常用的数学工具之一,能够帮助我们处理各种数学计算和插值运算。 Mathf…...

STM32CubeMX-H7-19-ESP8266通信(中)--单片机控制ESP8266实现TCP地址通信
前言 上篇文章我们已经能够使用串口助手实现esp8266的几种通信,接下来我们使用单片机控制实现。这篇文章会附带教程,增加.c和,.h,把串口和定时器放到对应的编号,然后调用初始化就可以使用了。 先讲解,然后末尾再放源码…...
ubuuntu24.04 编译安装 PostgreSQL15.6+postgis 3.4.2 + pgrouting 3.6.0 +lz4
文章目录 下载基础包下载源码包编译 PG编译 postgis编译安装 pgrouting下载源码包配置编译参数编译安装 初始化数据库建表并检查列是否使用了 lz4 压缩算法检查 postgis 与 pgrouting 是否可以成功创建 下载基础包 sudo apt update && sudo apt upgrade -y sudo apt i…...

【汇编逆向系列】四、函数调用包含单个参数之Double类型-mmword,movsd,mulsd,addsd指令,总结汇编的数据类型
一、汇编代码 上一节开始,讲到了很多debug编译独有的汇编方式,为了更好的区分release的编译器优化和debug的区别,从本章节开始将会提供debug和release的汇编用作对比 Debugb编译 single_double_param:00000000000000A0: F2 0F 11 44 24 08…...

【AI学习】wirelessGPT多任务无线基础模型摘要
收看了关于WirelessGPT多任务无线基础模型的演讲视频,边做一个记录。 应该说,在无线通信大模型的探索方面,有一个非常有益的尝试。 在沈学明院士带领下开展 https://www.chaspark.com/#/live/1125484184592834560...

docker 部署redis集群 配置
docker的网络模式 网桥模式每次重启容器都有可能导致容器ip地址变化,需要固定ip的自己自定义网络,这里介绍的是默认网络模式 docker创建容器 docker run --name redis6379 -p 6379:6379 -p 16379:16379 -v /etc/redis/redis6379:/etc/redis -d --r…...

Ansys Maxwell:线圈和磁体的静磁 3D 分析
本博客展示了如何在 Ansys Maxwell 中执行静磁 3D 分析,以计算载流线圈和永磁体之间相互作用产生的扭矩。在这个例子中,线圈中的电流产生一个沿 Y 轴指向的磁场,而永磁体沿 X 轴被磁化。这种配置导致围绕 Z 轴的扭矩。分步工作流程包括构建几…...
android 之 KeyguardService
一、功能定位与核心作用 KeyguardService 是 Android 锁屏功能的核心服务,负责管理设备锁屏界面(如密码、图案、指纹等验证流程),并协调系统安全策略与用户交互。主要职责包括: 锁屏状态管理 控制锁屏界面的显示/隐藏…...
compose 组件 ---无ui组件
在 Jetpack Compose 中,确实存在不直接参与 UI 渲染的组件,它们主要用于逻辑处理、状态管理或副作用控制。这些组件虽然没有视觉界面,但在架构中扮演重要角色。以下是常见的非 UI 组件及其用途: 1. 无 UI 的 Compose 组件分类 (…...

【计算机网络】SDN
SDN这种新型网络体系结构的核心思想:把网络的控制层面与数据层面分离,而让控制层面利用软件来控制数据层面中的许多设备。 OpenFlow协议可以被看成是SDN体系结构中控制层面与数据层面之间的通信接口。 在SDN中取代传统路由器中转发表的是“流表”&…...