create table test_innodb_insert_lock
(id int not null primary key auto_increment,
uk int not null unique key) engine = innodb;
開啟三個終端執行窗口,模擬三個session
session_1,insert成功
session_2,等待...
session_3,等待
Mysql(當前問題是在使用innodb引擎的前提下)的鎖種類很多,而insert時所涉及到的鎖情況較select、update、delete有所不同,相對更復雜一些。
mysql中如何保障uk的唯一性?肯定是加鎖。那在哪里加鎖?對誰加鎖?如果要操作的數據本身還不存在,那又該如何加鎖?
mysql是索引組織表,基于B+樹(多路有序平衡查找樹)來構建主鍵索引和二級索引。唯一索引也是二級索引,但其唯一性,幾乎等同于主鍵索引(所以如果表中沒有主鍵只有唯一鍵,唯一鍵是代替主鍵作用的)。所以mysql加鎖是在索引記錄上加鎖。
因為key由Session1創建,因而在該key上持有X-lock(排他鎖),而Session2和Session3內部獲取到DuplicateKey異常后,會先獲取S-lock(共享鎖,讀取該key),之后再嘗試升級鎖成X-lock,然后如果有機會的話,執行插入。這里的機會,是指Session1回滾并釋放了X-lock。下圖是Session1執行rollback后Session2、Session3的反應:
session_2,搶占成功insert OK
session_3,搶占失敗,DeadLock
當然,如果session1正常commit,session2和session3會報沖突