在我们的日常开发中,你是否遇到过这种情景:查看某条记录是否存在,不存在的话创建一条新记录,存在的话更新某些字段。你的处理方式是不是就是按照下面这样?

  1. $result = mysql_query('select * from xxx where id = 1');
  2. $row = mysql_fetch_assoc($result);
  3. if($row){
  4. mysql_query('update ...');
  5. }else{
  6. mysql_query('insert ...');
  7. }

这样的写法可能有如下几点缺陷:

  • 少量的性能消耗。执行了两次sql,按照一条sql一去一回两次网络传输的话,那么这就是4次。 
    * 麻烦。一个很简单的逻辑缺要写十来行代码。
  • 在高并发下会出问题。比如当我们获取到了需要的数据,在更新之前,有另外一个请求恰好删除了该条记录,我们的更新操作就没起到作用;再或者,如果我们更新操作的写法有问题,比如更新列a,我们使用a = $row[a] + 1而不是a = a +1这种原子性的操作,有可能别的请求已经修改过了该字段,从而造成数据出错。

幸好,MySql考虑到了这点,提供了insert … on duplicate key update的语法,该语法在insert的时候,如果insert的数据会引起唯一索引(包括主键索引)的冲突,即这个唯一值重复了,则不会执行insert操作,而执行后面的update操作。

例如,现在有表test,test表中有字段a,在a上有主键或者唯一索引,并且表中只有一条a=1, b=1的数据,现在执行如下的sql:

  1. insert into test (a,b) values (1,2) on duplicate key update b = b = 1;
  2. #因为a=1的记录已存在了,所以不会执行insert,而会在该条记录上执行update语言`b=b+1`,记录会变成a=1,b=2
  3. insert into test (a,b) values (2,2) on duplicate key update b = b + 1;
  4. #a=2的记录不存在,所以执行insert

这样我们就无需在应用程序里面再去判断记录是否存在了,也无需关系高并发下数据出错的情况了。

如果行作为新记录被插入,则受影响的行为1;如果原有记录被更新,则受影响行为2;如果原有记录已存在,但是更新的值和原有值相同,则受影响行为0。

多唯一索引冲突

为了测试方便,我们建了下面的数据表:

  1. create table test(
  2. a int not null primary key,
  3. b int not null UNIQUE key,
  4. c int not null
  5. )

为了测试两个唯一索引都冲突的情况,然后插入下面的数据:

  1. insert into test values(1,1,1), (2,2,2);

然后执行:

  1. insert into test values(1,2,3) on duplicate key update c = c + 1;

因为a和b都是唯一索引,插入的数据在两条记录上产生了冲突,然而执行后只有第一条记录被修改:

  1. mysql> select * from test;
  2. +---+---+---+
  3. | a | b | c |
  4. +---+---+---+
  5. | 1 | 1 | 2 |
  6. | 2 | 2 | 2 |
  7. +---+---+---+
  8. 2 rows in set (0.00 sec)

上面的语句等同于:

  1. update test set c=c+1 where a=1 or b = 2 limit 1;

如果a=1 or b =2匹配多条记录,只有第一条记录被更新。所以,一般情况下,我们应该避免在有多个唯一索引的表中使用on duplicate key update

使用values()方法

在update中可以使用values()方法引用在insert中的值,如:

  1. insert into test values(1,3,5) on duplicate key update c = values( c )+ 1;

该语句会使a=1的记录中c字段的值更新为6,因为values(c)的值是引用的insert部分的值,在这个例子中就是insert into test values(1,3,5) 中的5,所以最终更新的值为6。

last_insert_id()

如果表含有auto_increment字段,使用insert … on duplicate key update插入或更新后,last_insert_id()返回auto_increment字段的值。

并发控制

在使用例如MyISAM这样的表级锁的分区表上使用insert … on duplicate key update时,会锁住所有分区表,而在例如使用InnoDB这样的行级锁的分区表上则不会锁住所有分区表。

delayed选项

delayed选项会被忽略,当我们使用on duplicate key update时。

MySql之on duplicate key update详解的更多相关文章

  1. MySQL中ON DUPLICATE KEY UPDATE使用

    今天做推断插入用到了MySQL中ON DUPLICATE KEY UPDATE,如今Mark下面! 假设你想做到数据库中没有数据的话插入数据.有数据的话更新数据,那么你能够选择ON DUPLICATE ...

  2. MySQL于ON DUPLICATE KEY UPDATE采用

    今天我们做的推断插入用途MySQL于ON DUPLICATE KEY UPDATE.现在,Mark下面! 假设你想做的事,再有就是在数据库中插入数据没有数据.如果有数据更新数据,然后你可以选择ON D ...

  3. mysql优化 ON DUPLICATE KEY UPDATE

    场景:比如,有一张表,专门记录业务里的唯一数据记录,这张表里如果存在此唯一数据的记录就更新此行数据的某个字段,如果此唯一数据不存在,那么就添加一条最新数据. 一贯操作:如果不知道mysql有 ON D ...

  4. mysql INSERT ... ON DUPLICATE KEY UPDATE语句

    网上关于INSERT ... ON DUPLICATE KEY UPDATE大多数文章都是同一篇文章转来转去,首先这个语法的目的是为了解决重复性,当数据库中存在某个记录时,执行这条语句会更新它,而不存 ...

  5. mysql insert on duplicate key, update, ignore

    insert 语句中不能使用where,所以如果需要根据插入的数据在已有的数据库表是否重复做一些操作可以使用下面三种方法: 1. 使用insert,捕获duplicate错误 2. insert in ...

  6. mysql:on duplicate key update与replace into

    在往表里面插入数据的时候,经常需要:a.先判断数据是否存在于库里面:b.不存在则插入:c.存在则更新 一.replace into 前提:数据库里面必须有主键或唯一索引,不然replace into ...

  7. 【MySQL】ON DUPLICATE KEY UPDATE

    之前没用过这个操作,甚至没见过--最近接触到,而且还挺有用. 作用:若 KEY 不重复,则插入记录:否则更新记录. 单条操作: INSERT INTO table(a, b, c) VALUES (1 ...

  8. MySQL中insert ignore into, on duplicate key update,replace into,insert … select … where not exist的一些用法总结

    在MySQL中进行条件插入数据时,可能会用到以下语句,现小结一下.我们先建一个简单的表来作为测试: CREATE TABLE `books` ( `id` ) NOT NULL AUTO_INCREM ...

  9. mysql插入数据时 insert IGNORE、ON DUPLICATE KEY UPDATE、replace into

    转: mysql insert时几个操作DELAYED .IGNORE.ON DUPLICATE KEY UPDATE的区别 博客分类: mysql基础应用   mysql insert时几个操作DE ...

随机推荐

  1. 《More Effective C++ 》笔记

    条款10 防止构造函数里的资源泄露 条款20 协助编译器实现返回值优化 条款22 考虑使用op=来取代单独的op运算符 条款26 限制类对象的个数 条款27 要求或禁止对象分配在堆上

  2. Java中生成随机字符的方法总结

    package learnExercise; public class RandomCharacter { public static char getRandomCharacter(char ch1 ...

  3. PHP生成图片验证码(simple)

      php新手,写了一个web登录界面,除了用户名,密码,感觉有个验证码会比较cool一点,便根据参考书的简单介绍,写了一个image.php来生成简单的图片验证码,颇有感慨,分享一下. 1. 图片验 ...

  4. 使用Jmeter测试MySQL性能——(2)多客户端配置

    在测试性能过程中,单个测试客户端可能存在性能瓶颈无法达到测试要求的压力.在这种情况下,可以设置jmeter的多客户端模式,然后通过一台控制端,同时控制多台PC上的客户端向服务器发送测试请求.若有4台P ...

  5. Java自带的keytool命令

    使用Java自带的keytool命令,在命令行生成. 1.生成服务器端私钥kserver.keystore文件 keytool -genkey -alias serverkey -validity 1 ...

  6. clipToBounds

    最近在开发H5平台的iOS移动侧,遇到些问题,随手记录下来. 1 UIView的clipToBounds 窗口裁剪,默认是NO,表示如果父窗口的大小已经不足以显示子窗口,也不进行裁剪,而是显示,但这时 ...

  7. 转 用 AXIOM 促进 XML 处理

    转自:http://www.ibm.com/developerworks/cn/xml/x-axiom/ AXIOM 还不是另一种对象模型.它有着明确的设计目标:大幅提升 Apache 下一代 SOA ...

  8. Codeforces Round #128 (Div. 2)

    A. Two Problems 分两题的过题情况讨论,并且数值均不大,暴力枚举. B. Game on Paper 每次给格子染色后,考虑当前格子在正方形中的位置,然后判断对应的正方形是否都已染色. ...

  9. HTML初讲

    整理老师所讲: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...

  10. Mysql存储日期类型用int、timestamp还是datetime?

    通常存储时间用datetime类型,现在很多系统也用int存储时间,它们有什么区别?个人更喜欢使用int这样对于日期计算时比较好哦,下面我们一起来看到底那种会好些. int ().4个字节存储,INT ...