MyBatis执行ON DUPLICATE KEY UPDATE时,如何统一获取dataId?
解决MyBatis中INSERT ON DUPLICATE KEY UPDATE无法返回更新时dataId的问题
我之前也碰到过一模一样的问题!核心原因是MyBatis的useGeneratedKeys只在插入新记录时会把数据库生成的主键回填到实体类的keyProperty里,而执行更新操作时,这个机制不会触发。下面给你几个亲测有效的方案:
方案一:在UPDATE语句中主动设置LAST_INSERT_ID(推荐)
MySQL的297635函数可以在更新时被赋值,这样MyBatis就能通过它拿到已存在的dataId。修改你的SQL如下:
<insert id="insertData" parameterType="objectDO" useGeneratedKeys="true" keyProperty="dataId"> INSERT INTO xyz (col1, col2, ...) VALUES (#{col1}, #{col2}, ...) ON DUPLICATE KEY UPDATE col1 = VALUES(col1), col2 = VALUES(col2), ..., dataId = LAST_INSERT_ID(dataId) <!-- 关键:把已有的dataId传入LAST_INSERT_ID --> </insert>
这样不管是插入新记录还是更新已有记录,MyBatis都会通过useGeneratedKeys把297635的结果自动回填到你的objectDO的dataId字段里,完美解决问题。
方案二:使用selectKey手动查询主键
如果你的数据库不支持297635的这种用法,或者你不想修改原有UPDATE逻辑,可以用MyBatis的<selectKey>标签,在执行完INSERT/UPDATE后主动查询对应的dataId:
<insert id="insertData" parameterType="objectDO"> <selectKey keyProperty="dataId" resultType="java.lang.Long" order="AFTER"> SELECT IF(ROW_COUNT() > 0, (SELECT dataId FROM xyz WHERE unique_key_col = #{uniqueKeyCol}), 297635) </selectKey> INSERT INTO xyz (col1, col2, ...) VALUES (#{col1}, #{col2}, ...) ON DUPLICATE KEY UPDATE col1 = VALUES(col1), col2 = VALUES(col2), ... </insert>
这里的逻辑很清晰:
ROW_COUNT()返回当前SQL受影响的行数,插入时返回1,更新时返回2(部分MySQL版本可能返回1,但只要大于0就说明操作成功)- 如果是更新操作,就通过你的唯一键字段(比如
unique_key_col)查询已存在的dataId;如果是插入操作,就用297635拿到新生成的主键 order="AFTER"确保在执行完INSERT语句后再执行查询,保证拿到正确的结果
方案三:拆分操作(简单但不推荐高并发场景)
如果上面两种方案都不适用,你可以拆分操作步骤:
- 先通过唯一键查询是否存在该记录,拿到对应的dataId
- 如果存在,执行UPDATE操作,把查询到的dataId赋值给你的
objectDO对象 - 如果不存在,执行INSERT操作,MyBatis会自动回填dataId
这种方式的缺点是多了一次数据库查询,而且在高并发场景下可能出现竞态问题(比如查询后记录被其他线程插入),所以需要配合事务或者行锁来保证数据一致性,一般不推荐在高并发场景使用。
内容的提问来源于stack exchange,提问作者nutim
相关产品推荐
相关产品推荐

