两个并发事务想要对同一个KEY的数据进行更新,但是如果这个KEY的数据行还不存在的话,那么select .. for update当然不能锁住这行记录,想当然的想到,可不可以先insert一下,然后在悲观锁呢?
那么引入了一个新的问题,如果两个并发事务同时insert的话,就会插入重复的数据,如果insert的unique key重复的话,第二个线程会报错的,有没有更优雅的方法?
答案是MySQL innodb的INSERT ... ON DUPLICATE KEY UPDATE语法;
用法见官网文档:https://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html
If you specify ON DUPLICATE KEY UPDATE
, and a row is inserted that would cause a duplicate value in a UNIQUE
index or PRIMARY KEY
, MySQL performs an UPDATE
of the old row. For example, if column a
is declared as UNIQUE
and contains the value 1
, the following two statements have similar effect:
INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1; UPDATE table SET c=c+1 WHERE a=1;
使用ON DUPLICATE KEY UPDATE语法,第二条insert语句,会自动变成Update语句,而不会导致重复插入数据的BUG;
做个简单的测试:
CREATE TABLE `tcc` ( `idx` INT(11), `typeid` INT(11), `value1` INT(11), `value2` INT(11), UNIQUE KEY(idx, typeid) ) ENGINE=INNODB DEFAULT CHARSET=utf8; -- 第一条SQL的执行,会新增一条数据,本SQL多次执行,效果相同,因为后续的操作,变成了UPDATE INSERT INTO tcc (idx, typeid, value1) VALUES (1,2,3) ON DUPLICATE KEY UPDATE value1=3; -- 第二条SQL直接进行UPDATE,把新列的值update进去 INSERT INTO tcc (idx, typeid, value2) VALUES (1,2,4) ON DUPLICATE KEY UPDATE value2=4;
产出结果只有一条:
"idx" "typeid" "value1" "value2"
"1" "2" "3" "4"
有了这个利器,那么代码中就可以直接insert.. on duplicate key update,这个SQL的执行能保证数据库中会存在记录,然后加上悲观锁,来保证不同的事务不会出现更新冲突情况;
本文地址:http://crazyant.net/1835.html
[星星眼儿]更多劲爆的就在→ http://sebi.club