解决MySQL复合主键下ON DUPLICATE KEY UPDATE语句失效问题

先描述一下这个问题的起因,假设有一张表,里面保存了交易订单,每张订单有唯一的ID,有最后更新时间,还有数据,详情如下:

+-------+----------+------+-----+---------------------+-------+
| Field | Type     | Null | Key | Default             | Extra |
+-------+----------+------+-----+---------------------+-------+
| UID   | int(11)  | NO   | PRI | 0                   |       |
| Time  | datetime | NO   |     | 0000-00-00 00:00:00 |       |
| Data  | int(11)  | YES  |     | NULL                |       |
+-------+----------+------+-----+---------------------+-------+

针对这张表会做追加及更新的操作,具体来说就是如果订单不存在就INSERT一条新的,如果已存在就UPDATE。由于入库前无法得知相应记录是否已存在,通常的做法无法以下几种:

1、先SELECT一下,再决定INSERT还是UPDATE;

2、直接UPDATE,如果受影响行数是0,再INSERT;

3、直接INSERT,如果发生主键冲突,再UPDATE;

这几种方法都有缺陷,对MySQL来说其实最好的是直接利用INSERT...ON DUPLICATE KEY UPDATE...语句,具体到上面的test表,执行语句如下 :

INSERT INTO test VALUES (1, ‘2016-1-1‘, 10) ON DUPLICATE KEY UPDATE Time=‘2016-1-1‘,Data=10;

可以很好的插入或更新数据,一条语句就搞定,至此一直工作得很好。

后来因为查询方式变更,要求将UID和Time两个字段做联合主键,此时表结构如下:

+-------+----------+------+-----+---------------------+-------+
| Field | Type     | Null | Key | Default             | Extra |
+-------+----------+------+-----+---------------------+-------+
| UID   | int(11)  | NO   | PRI | 0                   |       |
| Time  | datetime | NO   | PRI | 0000-00-00 00:00:00 |       |
| Data  | int(11)  | YES  |     | NULL                |       |
+-------+----------+------+-----+---------------------+-------+

但是问题来了:一但Time字段被更新,即使是相同的UID,也被数据库认为是不同的主键,因此不会产生主键冲突,上面的语句就失效了,数据库里出现了很多UID相同的数据。

开始寻找解决办法,其实也简单,按MySQL文档里的说明,ON DUPLICATE KEY UPDATE语句判断是否冲突是依靠主键或唯一索引,因此为UID建立唯一索引就可以了。先建索引:

CREATE UNIQUE INDEX IDX_UID ON test(UID);

再测试一下插入:

INSERT INTO test VALUES (1, ‘2016-1-1‘, 10) ON DUPLICATE KEY UPDATE Time=‘2016-1-1‘,Data=10;
INSERT INTO test VALUES (1, ‘2016-2-1‘, 20) ON DUPLICATE KEY UPDATE Time=‘2016-2-1‘,Data=20;

检查数据库,可以看到不会有多条数据生成,唯一的一条数据是Data字段被更新成20的,成功。

时间: 2024-10-25 11:54:20

解决MySQL复合主键下ON DUPLICATE KEY UPDATE语句失效问题的相关文章

mysql insert语法注意事项(ON DUPLICATE KEY UPDATE )

mysql insert语法注意事项(ON DUPLICATE KEY UPDATE ) INSERT语法 INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name [(col_name,...)] VALUES ({expr | DEFAULT},...),(...),... [ ON DUPLICATE KEY UPDATE col_name=expr, ... ] 或: INSERT [LOW_PRIO

(转)replace 和 on duplicate key update语句

一.on duplicate key update语句 如果您指定了ON DUPLICATE KEY UPDATE,并且插入行后会导致在一个UNIQUE索引或PRIMARY KEY中出现重复值,则执行旧行UPDATE.例如,如果列a被定义为UNIQUE,并且包含值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

Mysql复合主键中自增长字段

Google Analytics的ID一般形如:UA-18xxxxx-1,UA-18xxxxx-4, 我们可以将它分成两段来看:字段1:UA-18XXXXX是指帐户的ID:字段2:字段1后附加的1.4,刚分别是指该帐户名下的两个网站.有一段时间很 纠结这样的ID怎么去维护,直到最近查阅到Mysql手册才发现,原来Mysql原生就很好的支持了这种含自动增长字段的复合主键,所以字段2是存储引擎 自动计算出来的.计算方式:MAX(auto_increment_column) + 1 WHERE pre

mysql的replace into和on duplicate key update测试笔记

mysql> create table tbl_insert_tmp(id int(5),addr_number int(10), name varchar(20),primary key (id),unique key udx_addr_number (addr_number));       Query OK, 0 rows affected (0.05 sec) mysql> show create table tbl_insert_tmp\G**********************

INSERT ... ON DUPLICATE KEY UPDATE Syntax

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 f

MySQL使用on duplicate key update时导致主键不连续自增

使用on duplicate key update语法有时是很方便,但是会有一个影响:默认情况下,每次更新都会更新该表的自增主键ID,如果更新频率很快,会导致主键ID自增的很快,过段时间就超过数字类型的的范围了解决这个问题,有两种方式:(实际目前的方式就是把自增主键ID设置为bigint,也有一部分操作先查询再选择插入OR更新)方法一:拆分成两个动作,先查询,再更新方法二:修改innodb_autoinc_lock_mode参数(不推荐)  innodb_autoinc_lock_mode中有3

[MySQL日记]主键唯一键重复插入解决方法

我们插入数据的时候,有可能碰到重复数据插入的问题,但是这些数据又是不被允许有重复值: CREATE TABLE stuInfo ( id INT NOT NULL COMMENT '序号', name VARCHAR(20) NOT NULL DEFAULT '' COMMENT '姓名', age INT NOT NULL DEFAULT 0 COMMENT '年龄', PRIMARY KEY (id), UNIQUE KEY uniq_name(name) ) ENGINE=InnoDB D

mysql数据库基础(2)索引、主键、复合主键、外键

增.删.改.查 加""表示为普通字符 mysql> insert into  t9 values("NULL",21,"game,flim"); +++++++++++++++++++++++++++++++ 添加新字段 mysql> alter table  t4 add age int(2) default 19;        //默认在最后面 mysql> alter table  t4 add mail char(50

对逻辑主键、业务主键和复合主键的思考

转载的: http://blog.csdn.net/sunrise918/article/details/5575054 这几天对逻辑主键.业务主键和复合主键进行了一些思考,也在网上搜索了一下相关的讨论,相关讨论可以看最下面的参考链接.下面是自己基于 SQL Server 做的一些总结,其他数据库(Oracle.MySQL.DB2.......)应该也类似吧.这个只是自己一时的思考,如有不当请告知,重新思考后再修 正. ? ? 定义(部分定义来源于 SQL Server 联机丛书): 主键(PR