MyBatis批量插入生成重复UUID主键问题求助
解决MyBatis批量插入时UUID主键重复的问题
这个问题我之前踩过一模一样的坑!核心原因是MyBatis在批量插入场景下,<selectKey>只会执行一次,而不是为集合中的每个元素单独生成UUID,导致所有插入记录共用同一个ID,自然就出现主键重复报错了。
下面给你几个亲测有效的解决方法,按需选择:
方法一:Java代码层提前生成UUID(最稳妥)
在调用MyBatis批量插入接口之前,手动为每个SysUser对象生成UUID并赋值。这种方式逻辑清晰,也能避免MyBatis批量处理特性带来的问题。
示例代码:
List<SysUser> userList = ...; // 待插入的用户列表 for (SysUser user : userList) { // 生成不带横线的UUID String uuid = UUID.randomUUID().toString().replace("-", ""); user.setId(uuid); } // 调用批量插入方法 userMapper.batchAdd(userList);
对应的MyBatis批量插入XML配置(不需要<selectKey>):
<insert id="batchAdd" parameterType="java.util.List"> insert into sys_user(id,user_name,user_email,user_info,user_password,create_time) values <foreach collection="list" item="user" separator=","> (#{user.id,jdbcType=VARCHAR}, #{user.userName,jdbcType=VARCHAR}, #{user.userEmail,jdbcType=VARCHAR}, #{user.userInfo,jdbcType=VARCHAR}, #{user.userPassword,jdbcType=VARCHAR}, #{user.createTime,jdbcType=TIMESTAMP}) </foreach> </insert>
方法二:在批量插入SQL中直接生成UUID(数据库层处理)
如果不想在代码层处理,可以直接在批量插入的SQL语句中,为每条记录调用数据库的UUID生成函数,这样每条插入都会生成独立的UUID。
示例XML配置:
<insert id="batchAdd" parameterType="java.util.List"> insert into sys_user(id,user_name,user_email,user_info,user_password,create_time) values <foreach collection="list" item="user" separator=","> (replace(uuid(),'-',''), #{user.userName,jdbcType=VARCHAR}, #{user.userEmail,jdbcType=VARCHAR}, #{user.userInfo,jdbcType=VARCHAR}, #{user.userPassword,jdbcType=VARCHAR}, #{user.createTime,jdbcType=TIMESTAMP}) </foreach> </insert>
这种方式的好处是不需要修改Java代码,完全由数据库负责ID生成,但要注意不同数据库的UUID函数可能有差异(比如MySQL用UUID(),Oracle也是UUID()但格式细节可能不同,需要根据你的数据库调整)。
为什么单条插入没问题?
单条插入时,MyBatis会在执行insert语句前,单独执行一次<selectKey>中的SQL,生成UUID并赋值给SysUser对象的id属性,所以不会重复。但批量插入时,MyBatis默认只会执行一次<selectKey>,导致所有元素共用同一个ID,这就是问题的根源。
内容的提问来源于stack exchange,提问作者kate




