`
hongtoushizi
  • 浏览: 378848 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

MySql之on duplicate key update详解

阅读更多

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

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

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

  • 少量的性能消耗。执行了两次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:

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

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

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

多唯一索引冲突

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

create table test(
	a int not null primary key,
	b int not null UNIQUE key,
	c int not null
)	

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

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

然后执行:

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

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

mysql> select * from test;
+---+---+---+
| a | b | c |
+---+---+---+
| 1 | 1 | 2 |
| 2 | 2 | 2 |
+---+---+---+
2 rows in set (0.00 sec)

上面的语句等同于:

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中的值,如:

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时。

 

转载自: http://zifeiwu.com/2013/10/13/mysql-on-duplicate-key-update.html

分享到:
评论

相关推荐

    mysql 批量更新及效率对比.docx

    `INSERT INTO tbl_name (col_name1, col_name2, ...) VALUES (col_value1, col_value2, ...), (col_value1, col_value2, ...) ON DUPLICATE KEY UPDATE userName = VALUES(userName), userID = VALUES(userID);...

    MySQL小技巧

    - **复合条件更新**: 如果想根据多个条件更新数据,可以使用`ON DUPLICATE KEY UPDATE`结合`WHERE`子句实现更复杂的逻辑。例如: ```sql INSERT INTO table(a,b,c) VALUES(1,2,3) ON DUPLICATE KEY UPDATE c=c+1 ...

    MySQL表的CRUD操作详解及实践案例

    Create主要涉及数据的新增、主键或唯一键的特殊处理方法如ON DUPLICATE KEY UPDATE 和 REPLACE INTO。Retrieve部分讲解了基于SELECT语句的数据查询技巧,重点在于WHERE条件的选择与构造,ORDER BY字段来排序结果集,...

    关于避免MySQL替换逻辑SQL的坑爹操作详解

    replace into和insert into on duplicate key 区别 replace的用法 当不冲突时相当于insert,其余列默认值 当key冲突时,自增列更新,replace冲突列,其余列默认值 Com_replace会加1 Innodb_rows_updated会加1 ...

    MySQL中replace into语句的用法详解

    当冲突发生时,`ON DUPLICATE KEY UPDATE`允许你指定要更新哪些列以及如何更新。 综上所述,`REPLACE INTO`是MySQL中处理数据插入和更新的一种高效方式,尤其适用于需要保持数据唯一性的场景。然而,它的行为可能会...

    Spring Boot性能优化:批量更新技术详解与效率提升指南.zip

    包括MyBatis-Plus提供的批量更新,JdbcTemplate提供的批量更新,在xml中循环拼接sql批量更新、case when语句批量更新、replace into方式批量更新、ON DUPLICATE KEY UPDATE批量更新。 适用于对Spring Boot和数据库...

    mysql 的replace into实例详解

    这使得`REPLACE INTO`更适合于希望保持数据唯一性的场景,而`INSERT INTO ON DUPLICATE KEY UPDATE`则更灵活,可以在保持唯一性的同时更新某些字段。 总的来说,`REPLACE INTO`是MySQL中处理数据插入和更新的一个...

    详解mysql DML语句的使用

    4. `ON DUPLICATE KEY UPDATE`:这是一种特殊的插入处理方式,当尝试插入的记录违反了唯一性约束(即存在重复的键值)时,会更新匹配的现有记录而不是抛出错误。例如: ``` INSERT INTO 表名 (列名1, 列名2 ...) ...

    Discuz X 数据库常用操作方法整理

    它可以接收一个包含数据的数组,以及是否返回插入ID、是否是替换式(即ON DUPLICATE KEY UPDATE)和是否静默执行的参数。例如,`DB::insert('tablename', $data_array, true, false, false)`将插入数据并返回新插入...

    190110419-李怡凯-实验一1

    1. 如果向actor表插入的数据中actor_id与已有数据重复,MySQL会抛出错误,提示“Duplicate entry '201' for key 'actor.PRIMARY'”,表示违反了主键的唯一性约束。 2. `NOW()`函数在INSERT语句中用于插入当前日期和...

Global site tag (gtag.js) - Google Analytics