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

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

+-------+----------+------+-----+---------------------+-------+
| 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。因为入库前没法得知相应记录是否已存在,一般的作法没法如下几种:数据库

一、先SELECT一下,再决定INSERT仍是UPDATE;ide

二、直接UPDATE,若是受影响行数是0,再INSERT;测试

三、直接INSERT,若是发生主键冲突,再UPDATE;spa

这几种方法都有缺陷,对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两个字段作联合主键,此时表结构以下:it

+-------+----------+------+-----+---------------------+-------+
| 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相同的数据。
class


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

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的,成功。

相关文章
相关标签/搜索