Mybatis 中ON DUPLICATE KEY UPDATE与useGeneratedKeys混用陷阱

探讨了在MyBatis中实现批量数据插入并更新唯一索引相同记录的方法,分享了一种结合INSERT...ON DUPLICATE KEY UPDATE语句的解决方案,以确保数据的正确性和效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近项目中遇到想要在唯一索引字段相同的情况下更新表中数据,并且返回主键ID的场景,此时我的写法是:

<insert id="batchInsert" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO op_clue_model_rule (rule_name, type, sql_str, rule_status, table_desc_list, 
    gmt_create_user, gmt_modified, gmt_modified_user, is_delete, remark)
    VALUES
    <foreach collection="list" item="item" index="index" separator=",">
        (#{item.ruleName,jdbcType=VARCHAR}, #{item.type,jdbcType=TINYINT}, 
        #{item.sqlStr,jdbcType=VARCHAR}, #{item.ruleStatus,jdbcType=TINYINT}, 
        #{item.tableDescList,jdbcType=VARCHAR}, #{item.gmtCreateUser,jdbcType=INTEGER}, now(), 
        #{item.gmtModifiedUser,jdbcType=INTEGER}, #{item.isDelete,jdbcType=TINYINT}, 
        #{item.remark,jdbcType=VARCHAR})
    </foreach>
    ON DUPLICATE KEY UPDATE
    sql_str = VALUES(sql_str),
    rule_status = VALUES(rule_status),
    table_desc_list = VALUES(table_desc_list),
    gmt_create_user = VALUES(gmt_create_user),
    gmt_modified_user = VALUES(gmt_modified_user),
    remark = VALUES(remark),
    gmt_create = now(),
    gmt_modified = now(),
    is_delete = 0
</insert>

这样的写法会造成一个严重的问题,这种写法不会返回主键,要想批量返回主键正确的写法是:

<insert id="batchInsert" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO op_clue_model_rule (rule_name, type, sql_str, rule_status, table_desc_list, 
    gmt_create_user, gmt_modified, gmt_modified_user, is_delete, remark)
    VALUES
    <foreach collection="list" item="item" index="index" separator=",">
        (#{item.ruleName,jdbcType=VARCHAR}, #{item.type,jdbcType=TINYINT}, 
        #{item.sqlStr,jdbcType=VARCHAR}, #{item.ruleStatus,jdbcType=TINYINT}, 
        #{item.tableDescList,jdbcType=VARCHAR}, #{item.gmtCreateUser,jdbcType=INTEGER}, now(), 
        #{item.gmtModifiedUser,jdbcType=INTEGER}, #{item.isDelete,jdbcType=TINYINT}, 
        #{item.remark,jdbcType=VARCHAR})
    </foreach>
</insert>

所以我现在既需要他批量返回主键,也需要他能在唯一索引字段相同的情况下更新数据。我的写法是:

<insert id="batchInsert" parameterType="java.util.List">
    INSERT INTO op_clue_model_rule (rule_name, type, sql_str, rule_status, table_desc_list, 
    gmt_create_user, gmt_modified, gmt_modified_user, is_delete, remark)
    VALUES
    <foreach collection="list" item="item" index="index" separator=",">
        (#{item.ruleName,jdbcType=VARCHAR}, #{item.type,jdbcType=TINYINT}, 
        #{item.sqlStr,jdbcType=VARCHAR}, #{item.ruleStatus,jdbcType=TINYINT}, 
        #{item.tableDescList,jdbcType=VARCHAR}, #{item.gmtCreateUser,jdbcType=INTEGER}, now(), 
        #{item.gmtModifiedUser,jdbcType=INTEGER}, #{item.isDelete,jdbcType=TINYINT}, 
        #{item.remark,jdbcType=VARCHAR})
    </foreach>
    ON DUPLICATE KEY UPDATE
    sql_str = VALUES(sql_str),
    rule_status = VALUES(rule_status),
    table_desc_list = VALUES(table_desc_list),
    gmt_create_user = VALUES(gmt_create_user),
    gmt_modified_user = VALUES(gmt_modified_user),
    remark = VALUES(remark),
    gmt_create = now(),
    gmt_modified = now(),
    is_delete = 0
</insert>

1、先将数据入库,如果唯一索引相同,更新。

2、通过联合唯一索引(ruleName、type)作为条件再去查询一下。(没啥办法吧?如果有办法请在评论区赐教)

MyBatis中,`ON DUPLICATE KEY UPDATE` 是一种数据库操作语句,用于在尝试插入一个新记录时,如果因为主键或唯一索引冲突而失败,则会执行一个更新操作。这种SQL语句特别适用于当你希望在记录已存在时更新该记录,而不存在时则插入新记录的场景。 在MyBatis中,你可以通过XML映射文件或注解的方式来使用`ON DUPLICATE KEY UPDATE`。以下是使用XML映射文件的一个示例: ```xml <insert id="insertOrUpdate" useGeneratedKeys="true" keyProperty="id"> INSERT INTO your_table (column1, column2, ...) VALUES (#{param1}, #{param2}, ...) ON DUPLICATE KEY UPDATE column1 = VALUES(column1), column2 = VALUES(column2) </insert> ``` 在这个例子中,`your_table`是你要插入或更新的表名,`column1`, `column2`等是你希望插入或更新的列名,`param1`, `param2`等是传递给映射方法的参数。当尝试插入一条记录时,如果`your_table`表中已存在具有相同主键或唯一索引值的记录,则会执行`ON DUPLICATE KEY UPDATE`后面的更新语句。 同样的逻辑也可以通过注解来实现,例如: ```java @Options(useGeneratedKeys = true, keyProperty = "id") @Insert("INSERT INTO your_table (column1, column2, ...) VALUES (#{param1}, #{param2}, ...)") @Update("UPDATE your_table SET column1 = #{param1}, column2 = #{param2}, ... WHERE id = #{id}") @SelectKey(statement="SELECT LAST_INSERT_ID()", keyProperty="id", before=false, resultType=int.class) public void insertOrUpdate(YourEntity entity); ``` 在这种方式下,当尝试插入数据时,如果出现重复键错误,MyBatis会自动根据`@Update`注解中定义的SQL语句来更新记录。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

地表最强菜鸡

你的鼓励将是我创作最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值