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

相關文章
相關標籤/搜索