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

摘要:
后来因为查询方式变更,要求将UID和Time两个字段做联合主键,此时表结构如下:1234567+-------+----------+------+-----+---------------------+-------+|Field|Type|Null|Key|Default|Extra|+-------+----------+------+-----+---------------------+-------+|UID|int|NO|PRI|0|||Time|datetime|NO|PRI|0000-00-0000:00:00|||Data|int|YES||NULL||+-------+----------+------+-----+---------------------+-------+但是问题来了:一但Time字段被更新,即使是相同的UID,也被数据库认为是不同的主键,因此不会产生主键冲突,上面的语句就失效了,数据库里出现了很多UID相同的数据。

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

1
2
3
4
5
6
7
+-------+----------+------+-----+---------------------+-------+
|Field|Type|Null|Key|Default|Extra|
+-------+----------+------+-----+---------------------+-------+
|UID|int(11)|NO|PRI|0||
|Time|datetime|NO||0000-00-0000: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表,执行语句如下 :

1
INSERTINTOtestVALUES(1,'2016-1-1',10)ONDUPLICATEKEYUPDATETime='2016-1-1',Data=10;

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

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

1
2
3
4
5
6
7
+-------+----------+------+-----+---------------------+-------+
|Field|Type|Null|Key|Default|Extra|
+-------+----------+------+-----+---------------------+-------+
|UID|int(11)|NO|PRI|0||
|Time|datetime|NO|PRI|0000-00-0000:00:00||
|Data|int(11)|YES||NULL||
+-------+----------+------+-----+---------------------+-------+

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

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

1
CREATEUNIQUEINDEXIDX_UIDONtest(UID);

再测试一下插入:

1
2
INSERTINTOtestVALUES(1,'2016-1-1',10)ONDUPLICATEKEYUPDATETime='2016-1-1',Data=10;
INSERTINTOtestVALUES(1,'2016-2-1',20)ONDUPLICATEKEYUPDATETime='2016-2-1',Data=20;

免责声明:文章转载自《MySQL复合主键下ON DUPLICATE KEY UPDATE语句失效问题》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇如何彻底禁止火狐浏览器/谷歌浏览器的自动更新(附浏览器各版本与驱动下载链接)UIScrollView 原理详解下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Python 第四十二章 mysql 级联+查询

删除或修改被关联字段 场景:book表和publish表为多对一关系,book表的pid字段外键关联到了publish表的id字段 1 查看外键关系名称: show create table book; | book | CREATE TABLE `book` ( `id` int(11) NOT NULL AUT...

phpstudy 升级(更换) mysql 版本

原文链接:http://phpstudy.php.cn/jishu-php-3131.html 一、下载新版 mysql 例如 mysql5.7: https://dev.mysql.com/downloads/file/?id=467269 二、备份 phpStudyPHPTutorialMySQL 三、解压下载的新版 mysql,放于 phpStudy...

MySQL -- Innodb是如何处理自增列的

对于那些向带有自增列的表中插入行的语句,Innodb提供一种可配置的锁定机制,这种锁定机制可以显著提高SQL语句的可伸缩性和性能。 Innodb中为了使用自增机制,自增列必须是索引的部份,从而可以使用等价查询。典型的做法是将自增列放在表的索引的第一个位置。   Innodb自增锁模式 自增锁模式是在启动的时候由参数innodb_autoinc_lock_m...

Linux如何查看YUM的安装目录

https://www.cnblogs.com/kerrycode/p/6924153.html https://blog.csdn.net/wd2014610/article/details/79659073 Linux下如何查看使用YUM安装过的包的安装路径呢? 在搞清楚这个问题前,我们先来了解一下YUM。 YUM(全称为 Yellow dog Up...

MySQL varchar 最大长度,text 类型占用空间剖析

MySQL 表中行的最大大小为 65,534(实际行存储从第二个字节开始)字节。每个 BLOB 和 TEXT 列只占其中的 5 至 9 个字节。 那么来验证下 varchar 类型的实际最大长度:测试环境:MySQL版本 5.7.19 //首先要设置下 mysql 为严格执行模式,不然 varchar 超出最大长度为自动转为 text 类型 set sql...

解决mac上mysql莫名其妙的启动不了

在OS X环境下MySQL启动时报错: 1 2 016-03-03T00:02:30.483037Z 0 [ERROR] InnoDB: Unable tolock ./ibdata1 error: 35 2016-03-03T00:02:30.483100Z 0 [Note] InnoDB: Checkthat you do notalre...