mysql 使用insert into select....on duplicate key update 语句时,返回多条结果,值被最后一条数据覆盖问题解决

在MySQL中遇到使用INSERT INTO SELECT...ON DUPLICATE KEY UPDATE时,发现多条数据被最后一条覆盖的问题。解决方案是确保在MySQL 8.0.20之前版本使用VALUES(列名)语法。此外,8.0.20之后版本需使用列别名,同时注意保持插入顺序一致以避免结果不一致的bug,并为涉及的where、orderby、groupby字段建立索引以优化性能。

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

 问题:最近在工作中,使用insert into select....on duplicate  key update 语句时,返回多条结果,值被最后一条数据覆盖问题

 解决:直到最终查了官方文档才知道:mysql版本 在8.0.20之前要使用以下代码形式

ON DUPLICATE KEY UPDATE month_money=VALUES(month_money),my_commission=VALUES(my_commission) ; 
-- VALUES(列名)

#### 其它问题
#### ON DUPLICATE KEY UPDATE :mysql版本 8.0.20时应该使用别名,但是当前的mysql版本是8.0.11 应该使用VALUES(列名)的形式,这样不会造成返回多条数据时,最后一条的值覆盖前面的值
#### 使用INSERT INTO SELECT....ON DUPLICATE KEY UPDATE 语句时,如果需要保证插入顺序与原表一样,要加入order by 语句,否则会产生结果不一致的莫名bug【mysq 8 已知bug】
#### 使用INSERT INTO SELECT....ON DUPLICATE KEY UPDATE 语句时,要注意创建相关where,order by,group by 的字段的索引,避免全表扫描造成锁表

 

### 使用 MyBatis 进行 `INSERT INTO ... ON DUPLICATE KEY UPDATE` 的解决方案 当使用 MyBatis 的 `SqlSession.insert()` 方法执行带有 `ON DUPLICATE KEY UPDATE` 语句的操作,可能会遇到 `UnsupportedOperationException` 异常。这是因为 MyBatis 默认的 `insert()` 方法仅支持标准的插入操作而不直接支持复杂的 SQL 语法。 以下是解决问题的方法: #### 方法一:自定义 Mapper 接口并配置动态 SQL 可以通过在 XML 映射文件中编写 `<update>` 节点来实现复杂逻辑。MyBatis 支持通过 `<update>` 来完成 `INSERT INTO ... ON DUPLICATE KEY UPDATE` 操作。 ```xml <update id="batchInsertOrUpdate" parameterType="java.util.List"> INSERT INTO your_table (column1, column2, column3) VALUES <foreach collection="list" item="item" separator=","> (#{item.column1}, #{item.column2}, #{item.column3}) </foreach> ON DUPLICATE KEY UPDATE column1 = VALUES(column1), column2 = VALUES(column2), column3 = VALUES(column3); </update> ``` 上述代码片段展示了如何利用 MyBatis 的 `<foreach>` 动态标签构建批量插入语句,并结合 MySQL 提供的 `ON DUPLICATE KEY UPDATE` 实现更新功能[^1]。 调用此方法需注意: - 参数应为列表对象。 - 数据库表结构中的唯一键约束必须已正确定义以便触发冲突检测。 #### 方法二:手动管理事务 如果需要更灵活地控制事务行为,则可以显式开启事务并通过 JDBC API 或者 Spring AOP 配合 MyBatis 完成操作。例如,在 Java 中可如下设置事务模式: ```java try { sqlSession.getConnection().setAutoCommit(false); // 设置自动提交关闭 sqlSession.update("namespace.batchInsertOrUpdate", dataList); // 执行批处理SQL sqlSession.commit(); // 提交事务 } catch (Exception e) { sqlSession.rollback(); // 出错则回滚 } ``` 这里的关键在于调整连接属性以允许程序级事务管理。 #### 方法三:借助存储过程或函数 对于某些场景下频繁使用的业务逻辑,考虑将其封装到数据库端作为存储过程或者触发器可能更为高效。比如之前提到的一个 PostgreSQL 自定义间戳更新的例子就可以扩展应用于此处[^2]。 创建类似的触发器能够简化应用程序层面对重复记录更新的需求: ```sql CREATE OR REPLACE FUNCTION handle_duplicate_insert() RETURNS TRIGGER AS $$ BEGIN IF EXISTS(SELECT 1 FROM your_table WHERE unique_key_column = NEW.unique_key_column) THEN UPDATE your_table SET ... WHERE unique_key_column = NEW.unique_key_column; ELSE INSERT INTO your_table (...) VALUES (...); END IF; RETURN NULL; -- result is ignored since this is an AFTER trigger END; $$ LANGUAGE plpgsql; -- 创建触发器绑定至目标表上 CREATE TRIGGER before_your_table_update_or_insert BEFORE INSERT ON your_table FOR EACH ROW EXECUTE PROCEDURE handle_duplicate_insert(); ``` 这种方法虽然增加了数据库负载但减少了客户端编码工作量以及潜在错误风险。 --- ### 总结 针对 MyBatis 在执行带 `ON DUPLICATE KEY UPDATE` 的批量插入/更新过程中抛出 `UnsupportedOperationException` 的情况,推荐采用以上三种策略之一加以应对。具体选择取决于项目实际需求和技术栈偏好等因素综合考量决定。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值