create table test_innodb_insert_lock
(id int not null primary key auto_increment,
uk int not null unique key) engine = innodb;
開啟三個(gè)終端執(zhí)行窗口,模擬三個(gè)session

session_1,insert成功

session_2,等待...

session_3,等待
Mysql(當(dāng)前問題是在使用innodb引擎的前提下)的鎖種類很多,而insert時(shí)所涉及到的鎖情況較select、update、delete有所不同,相對更復(fù)雜一些。
mysql中如何保障uk的唯一性?肯定是加鎖。那在哪里加鎖?對誰加鎖?如果要操作的數(shù)據(jù)本身還不存在,那又該如何加鎖?
mysql是索引組織表,基于B+樹(多路有序平衡查找樹)來構(gòu)建主鍵索引和二級索引。唯一索引也是二級索引,但其唯一性,幾乎等同于主鍵索引(所以如果表中沒有主鍵只有唯一鍵,唯一鍵是代替主鍵作用的)。所以mysql加鎖是在索引記錄上加鎖。
因?yàn)閗ey由Session1創(chuàng)建,因而在該key上持有X-lock(排他鎖),而Session2和Session3內(nèi)部獲取到DuplicateKey異常后,會先獲取S-lock(共享鎖,讀取該key),之后再嘗試升級鎖成X-lock,然后如果有機(jī)會的話,執(zhí)行插入。這里的機(jī)會,是指Session1回滾并釋放了X-lock。下圖是Session1執(zhí)行rollback后Session2、Session3的反應(yīng):

session_2,搶占成功insert OK

session_3,搶占失敗,DeadLock
當(dāng)然,如果session1正常commit,session2和session3會報(bào)沖突
