1. 程式人生 > >MySQL的Replace into 與Insert into on duplicate key update真正的不同之處

MySQL的Replace into 與Insert into on duplicate key update真正的不同之處

相同點:

(1)沒有key的時候,replace與insert .. on deplicate udpate相同。
(2)有key的時候,都保留主鍵值,並且auto_increment自動+1。

不同點

 有key的時候,replace是delete老記錄,而錄入新的記錄,所以原有的所有記錄會被清除,這個時候,如果replace語句的欄位不全的話,有些原有的比如例子中c欄位的值會被自動填充為預設值。
 
  而insert .. deplicate update則只執行update標記之後的sql,從表象上來看相當於一個簡單的update語句。
 但是實際上,根據我推測,如果是簡單的update語句,auto_increment不會+1,應該也是先delete,再insert的操作,只是在insert的過程中保留除update後面欄位以外的所有欄位的值。

 所以兩者的區別只有一個,insert .. on deplicate udpate保留了所有欄位的舊值,再覆蓋然後一起insert進去,而replace沒有保留舊值,直接刪除再insert新值。
 
 從底層執行效率上來講,replace要比insert .. on deplicate update效率要高,但是在寫replace的時候,欄位要寫全,防止老的欄位資料被刪除。

例子

建立測試表:

create table test (auto_id int auto_increment primary key, code int, times int, name VARCHAR
(10), unique key (code));
INSERT INTO `test` (`code`, `times`, `name`) VALUES ('100', 1, 'wo');

這裡寫圖片描述
常規的insert into隻影響了一行。test表的資料:
這裡寫圖片描述

1、 Replace into …
REPLACE into 已經存在的key時:

REPLACE into `test` (`code`, `times`) VALUES ('100', 1);

這裡寫圖片描述
影響了2行。test表的資料:
這裡寫圖片描述
明顯, auto_id自增1,name值為空,times則更新為2了。這說明當與key衝突時,replace覆蓋相關欄位,其它欄位填充預設值,可以理解為刪除重複key的記錄,新插入一條記錄,該語句做了 delete + insert 的操作,所以該語句影響了2行。

REPLACE into 不存在的key時:

REPLACE into `test` (`code`, `times`, 'name') VALUES (200, 1, '你');

這裡寫圖片描述
隻影響了一行,相當於只做了insert操作。test表資料:
這裡寫圖片描述

2、 Insert into on duplicate key update
已存在的key:

INSERT INTO `test` (`code`, `times`, `name`) VALUES (200, 2, 'wo') on DUPLICATE key update times = times + 1;

這裡寫圖片描述
影響了2行。test表的資料:
這裡寫圖片描述
明顯,name不變,times則更新為2了。這說明當與key衝突時,replace覆蓋相關欄位,其它欄位保留原有值,可以理解為刪除重複key的記錄,新插入一條記錄,該語句做了 delete + insert 的操作,所以該語句影響了2行。至於auto_id有沒有自增,我們看一下他插入一條不存在的key時,看一下auto_id。如果有自增,下一條記錄的auto_id為5,否者為4。

不存在的key:

INSERT INTO `test` (`code`, `times`, `name`) VALUES (300, 1, '你') on DUPLICATE key update times = times + 1;

這裡寫圖片描述
受影響1行。test表資料:
這裡寫圖片描述
顯然,Insert into on duplicate key update已經存在的key時,會自增長key會自增。不存在的key時,相當於只做了insert操作。

根據上面例子可以發現,結論正如我們在開頭所列舉的相同點和不同點。

MySQL 鎖模式

對於普通的INSERT操作,當需要檢查duplicate key時,加LOCK_S鎖,即共享(S)鎖,而對於Replace into 或者 INSERT..ON DUPLICATE操作,則加LOCK_X記錄鎖,也就是排他(X)鎖。

InnoDB 實現了標準行級鎖, 他有兩種鎖, 共享(S)鎖和排他(X)鎖. 需要看record, gap, next-key鎖型別, 參照 xxx

  • A shared (S) lock permits the transaction that holds the lock to read a row.
  • 一個共享鎖允許事務獲取鎖來讀取一行

  • An exclusive (X) lock permits the transaction that holds the lock to update or delete a row.

  • 一個排他鎖允許事務獲取鎖來更新或刪除一行

從字面的意思理解如下:
1、如果事務T1持有對行 r 的 S 鎖, 那麼另外一個事務T2對行 r 的請求會被馬上授權.因此, T1 T2都對r持有一個共享鎖。

2、如果一個事務T1持有一個r的X鎖, 那麼T2對r的任何鎖型別都無法被馬上授權. 替代的是T2必須等待T1釋放他在r上的鎖。

意向鎖(Intention Locks)
另外, InnoDB支援多重粒度加鎖, 這允許行鎖和表所共存. 為了讓多重粒度鎖定具有實用性, 另外一種叫做意向鎖的鎖會被使用. 意向鎖在InnoDB中是表鎖, 他表明S或X鎖將會在一個事務中對某一行使用. InnoDB有兩種意向鎖(假設事務T已經請求了表t的一個鎖)

  • Intention shared (IS): Transaction T intends to set S locks on individual rows in table t.
  • 意向共享鎖(IS): 事務T打算設定S鎖到表t上

  • Intention exclusive (IX): Transaction T intends to set X locks on those rows.

  • 意向排他鎖(IX): 事務T打算設定X鎖到行上

意向鎖協議如下
- 意向共享鎖(IS): 在一個事務獲取表t的某行的S鎖之前, 他必須獲取表t的一個IS鎖或更強的鎖
- 意向排他鎖(IX): 在一個事務獲取表t某行的X鎖之前, 他必須獲取一個t的IX鎖

一個鎖如果和已經存在的鎖相容, 就可以授權給請求他的事務, 但如果和已存在的鎖不相容則不行.一個事務必須等待直到衝突的鎖被釋放.如果一個鎖請求和一個已經存在的鎖衝突, 並且一直不能被授權, 就會造成死鎖.

因此, 意向鎖並不會阻塞任何事情, 除非是對全表的請求(例如, LOCK TABLES … WRITE). IX和IS鎖的主要目的是表示有人正在鎖定一行, 或者準備鎖定一行.