Mysqlonduplicatekeyupdate⽤法及优缺点
在实际应⽤中,经常碰到导⼊数据的功能,当导⼊的数据不存在时则进⾏添加,有修改时则进⾏更新,
在刚碰到的时候,⼀般思路是将其实现分为两块,分别是判断增加,判断更新,后来发现在mysql中有ON DUPLICATE KEY UPDATE ⼀步就可以完成(Mysql独有的语法)。
ON DUPLICATE KEY UPDATE单个增加更新及批量增加更新的sql
在MySQL数据库中,如果在insert语句后⾯带上ON DUPLICATE KEY UPDATE ⼦句,⽽要插⼊的⾏与表中现有记录的惟⼀索引或主键中产⽣重复值,那么就会发⽣旧⾏的更新;如果插⼊的⾏数据与现有表中记录的唯⼀索引或者主键不重复,则执⾏新纪录插⼊操作。
说通俗点就是数据库中存在某个记录时,执⾏这个语句会更新,⽽不存在这条记录时,就会插⼊。
注意点:
因为这是个插⼊语句,所以不能加where条件。
如果是插⼊操作,受到影响⾏的值为1;如果更新操作,受到影响⾏的值为2;如果更新的数据和已有的数据⼀样(就相当于没变,所有值保持不变),受到影响的⾏的值为0。
该语句是基于唯⼀索引或主键使⽤,⽐如⼀个字段a被加上了unique index,并且表中已经存在了⼀条记录值为1,
下⾯两个语句会有相同的效果:
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 INTO table (a,b,c) VALUES (1,2,3),(4,5,6)
批量更新sql语句ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);
表中将更改(增加或修改)两条记录。
项⽬中数据的操作有时候会令⼈头⼤,遇到⼀个需求:
需要将数据从A数据库的a数据表同步到B数据库的b数据表中(ab表结构相同,但不是主从关系。。。just同步过去)
第⼀次同步过去,b表为空,同步很简单。
但是当a表中的某些数据更新且增加了新数据之后,再想让两个表同步就有些⿇烦了。(如果把b表清空,重新同步,数据量过⼤的话耗费的时间太长,不是⼀个好办法)
想着能不能按照时间段来做更新,这段时间内有新数据了,就插⼊数据,有数据更新了就更新数据。先说下我的思路:
步骤:
1.⾸先我从a表取出某⼀时间段的数据(分段更新)
2.往b表内放数据,根据主键判断b表是否已经有此条记录,没有此数据则插⼊,有了记录则对⽐数据是否⼀样,⼀样则不做更改,不⼀样就做更新操作。
此时使⽤该语句可以满⾜需要,但是要注意⼏个问题:
更新的内容中unique key或者primary key最好保证⼀个,不然不能保证语句执⾏正确(有任意⼀个unique key重复就会⾛更新,当然如果更新的语句中在表中也有重复校验的字段,那么也不会更新成功⽽导致报错,只有当该条语句没有任何⼀个unique key重复才会插⼊新记录);尽量不对存在多个唯⼀键的table使⽤该语句,避免可能导致数据错乱。
在有可能有并发事务执⾏的insert 语句情况下不使⽤该语句,可能导致产⽣death lock。
如果数据表id是⾃动递增的不建议使⽤该语句;id不连续,如果前⾯更新的⽐较多,新增的下⼀条会相应跳跃的更⼤。
该语句是mysql独有的语法,如果可能会设计到其他数据库语⾔跨库要谨慎使⽤。
产⽣death lock原理
insert ... on duplicate key 在执⾏时,innodb引擎会先判断插⼊的⾏是否产⽣重复key错误,如果存在,在对该现有的⾏加上
S(共享锁)锁,如果返回该⾏数据给mysql,然后mysql执⾏完duplicate后的update操作,然后对该记录加上X(排他锁),最后进⾏update写⼊。
如果有两个事务并发的执⾏同样的语句,那么就会产⽣death lock,如:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论