MySQL不使用DUPLICATE语法 多条件判断存在更新否则插入咨询
问题结论
你编写的SQL不可行,原因如下:
SELECT语句仅用于数据查询,无法直接执行UPDATE/INSERT这类DML修改操作- MySQL的
IF表达式只能返回值,不支持嵌套执行DML语句,该写法本身就存在语法错误
正确实现方案
方案1:优先添加联合唯一键(推荐)
如果业务逻辑本身要求student_id + date的组合唯一(不存在同一个学生同一天有多条考勤记录的合理场景),优先给表加联合唯一约束:
ALTER TABLE `attendance` ADD UNIQUE KEY `uk_stu_date` (`student_id`, `date`);
之后直接用ON DUPLICATE KEY UPDATE语法实现需求,性能最高且天然支持原子性:
INSERT INTO `attendance` (`student_id`, `date`, `attendance`) VALUES (7, '2021-10-04', 0) ON DUPLICATE KEY UPDATE `attendance` = 0;
方案2:确实无法加唯一键的实现方式
如果因业务特殊原因不能加联合唯一键,用以下两种方法实现:
方式A:先查询后判断执行
适合并发量极低的场景:
- 先执行查询判断记录是否存在:
SELECT COUNT(*) AS cnt FROM `attendance` WHERE student_id = 7 AND `date` = '2021-10-04';
- 如果返回的
cnt大于0,执行UPDATE:
UPDATE `attendance` SET `attendance` = 0 WHERE student_id = 7 AND `date` = '2021-10-04';
- 如果返回的
cnt等于0,执行INSERT:
INSERT INTO `attendance` (`student_id`, `date`, `attendance`) VALUES (7, '2021-10-04', 0);
注意:高并发场景下这种写法会出现竞态条件,可能插入重复数据,需要配合事务+锁使用。
方式B:事务包裹先更新后插入
比先查后改少一次查询,性能更好:
-- 开启事务 START TRANSACTION; -- 先执行更新 UPDATE `attendance` SET `attendance` = 0 WHERE student_id = 7 AND `date` = '2021-10-04'; -- 判断更新行数,如果为0则执行插入 IF ROW_COUNT() = 0 THEN INSERT INTO `attendance` (`student_id`, `date`, `attendance`) VALUES (7, '2021-10-04', 0); END IF; -- 提交事务 COMMIT;
如果是在应用代码中实现,逻辑同理:先执行UPDATE,拿到驱动返回的影响行数,若为0再执行INSERT即可。
内容的提问来源于stack exchange,提问作者Shiv
相关产品推荐
相关产品推荐

