假設現在我們有這樣的需求:當數據庫中不存在滿足條件的記錄時,可以插入一條記錄,否則程序退出。該怎么實現?
1年以上工作經驗的人應該都能立即想到:去檢查一下庫里有沒有記錄,沒有就插入,有就結束。
int count = selectFromDb(); // ①
if count > 0 {
return;
} else {
insertIntoDb(); // ②
}
2年以上工作經驗的在寫完上面的邏輯后會立即發現:在並發場景下這樣並不安全。如果兩個線程同時執行到①這里,都會發現數據庫沒有記錄,於是分別執行了②。所以在並發場景下,這里需要使用分布式鎖。
int count = selectFromDb(); // ①
if count > 0 {
return;
} else {
try (getLock()) {// ③
count = selectFromDb(); // ④
if (count == 0) {
insertIntoDb(); // ②
}
}
}
這里在③處加了分布式鎖,然后看一下的確沒有數據再插入。
這篇文章要說的是使用數據庫的sql執行機制來保證並發鎖的實現。當然了,如果條件允許,使用唯一鍵沖突也是可以的。
在我們日常處理數據的時候,都是可以使用條件的,比如最簡單的select where,最普通的update where等等。如果我們在插入的時候也可以使用where這個問題不就解決了嗎。
當然了,正因為mysql沒有提供這種語法,所以我們才在這里討論這個問題。
mysql提供了根據已有數據來插入表的機制,就是非著名的insert select。所以我們的突破口就在這里,既然這里有select我們就在這里的select加where,因為insert select的實現是select不出東西的時候是不會插入的。
所以這里我們這樣寫
insert into t(id, c1, c2) select 1, "","" from dual where not exists (select * from t where c1="")
這里的where c1=""
假設就是我們的條件①。