視頻串講大型翻車現(xiàn)場:記錄存在的話就更新,記錄不存在的話就插入

那我們繼續(xù)
,還是這道場景題:現(xiàn)在我的業(yè)務中有這樣的需求:如果目標記錄存在的話我就更新它,如果記錄不存在的話我就插入。說說看你知道哪些實現(xiàn)方式吧!

這種方式。
// 偽代碼user=User.FindById(1)if user == null{user.Insert()}else{user.Update()}




比如這樣的例子:商品有上線和下線的狀態(tài),然后管理員可以在后臺頁面中修改商品的狀態(tài),比如代碼這樣寫的:
//?偽代碼,如果將狀態(tài)置反if?product.Status?==?“online”{???product.Status?=?"offline";}else{???product.Status?=?"online";??}

這時管理員A、B并發(fā)的去操作商品狀態(tài):

嗯,確實存在這種情況
,不過我可以自定義FindById()中的sql語句,通過 select for update的方式,規(guī)避你在圖畫出來的風險。

比如自定義SQL,讓 user = User.FindByID(1)函數(shù)執(zhí)行的SQL為
select * from user where id = 1 for update;
直接select時會給id = 1的行添加一把讀鎖,現(xiàn)在我通過select for update檢索,在讀select時給id = 的行添加寫鎖。
那么當我在讀取使用這行數(shù)據(jù)時,其他的人select for update
就會被阻塞,因為寫鎖之間彼此是互


哦?那你畫一個時序圖出來瞧瞧
嗯嗯,時序圖大概長下面這樣



嗯,乍一看你上面畫的這個圖是沒問題的
,但我有個問題:如果id = xx的行不存在呢?

嗯,所以我們不如分不同情況討論一下
。下面我列舉不同場景,你畫時序圖怎樣?
嗯嗯,好的!?


嗯!首先我們知道了,select for update會嘗試添加X鎖,也就是寫鎖。
常見的寫鎖有這么幾種:
1、record lock?給指定行記錄添加鎖
2、gap lock?間隙鎖
3、next key lock?
下面通過在不同條件下執(zhí)行select for update sql,再觀察實驗結果,就能八九不離十的推測出for update的加鎖情況。

實驗一已知條件如下:
create table t(a int,b int,primary key(a),key(b));insert into t select 1,1;insert into t select 3,1;insert into t select 5,3;insert into t select 7,6;insert into t select 10,8;

select for update sql為:
select?*?from?t?where?a=?5?for?update;提示:注意id=5的行已經(jīng)存在了。
下面你畫一下時序圖吧
嗯嗯,時序圖加鎖情況如下:



嗯,那如果我們需要執(zhí)行的sql如下:
select?*?from?t?where?b?=?3?for?update;注意b并不是唯一鍵,它只是一個普通索引哦!
你能畫一下它的加鎖時序圖嗎?
嗯嗯,時序圖如下:

(最后一條Sql條件是 where a = 5,不是a=3)


還是使用這些數(shù)據(jù)
create table t(a int,b int,primary key(a),key(b));insert into t select 1,1;insert into t select 3,1;insert into t select 5,3;insert into t select 7,6;insert into t select 10,8;
假如我執(zhí)行的sql是:
select?*?from?t?where?a?=?13?for?update;注意:
1、a=13的行并不存在哦!
2、a是唯一索引
你畫一下它的時序圖吧!
嗯呢,時序圖如下:



還是使用這些數(shù)據(jù)
create table t(a int,b int,primary key(a),key(b));insert into t select 1,1;insert into t select 3,1;insert into t select 5,3;insert into t select 7,6;insert into t select 10,8;
假如我執(zhí)行的sql是:
select?*?from?t?where?a?=?8?for?update;注意:
1、a=8的行并不存在哦!
2、a是唯一索引
你畫一下它的時序圖吧!
嗯嗯、如下:

對唯一索引來說,gap的上下都鎖不?。?/p>


還是使用這些數(shù)據(jù)
create table t(a int,b int,primary key(a),key(b));insert into t select 1,1;insert into t select 3,1;insert into t select 5,3;insert into t select 7,6;insert into t select 10,8;
假如我執(zhí)行的sql是:
select?*?from?t?where?b?=?5?for?update;注意:
1、b=5的行并不存在哦!
2、b是普通索引
你畫一下它的時序圖吧!
嗯嗯、如下。

對普通索引來說,gap鎖會 鎖上不鎖下!


嗯,對的?;氐轿覀円婚_始的主題:如果數(shù)據(jù)存在我們就update
數(shù)據(jù)不存在我們就insert的話題來看的話。
通過如下方案:
begin;select for update;# insert?or?update;commit;
是可以保證并發(fā)修改的安全性的....
嗯嗯、其實通過實驗來看,確實是安全的。


小伙子可以的!整體感覺還不錯。
歡迎關注我
。不久會給你安排下一面
。
我沒有問題了,你有什么想問我的嗎?
暫時沒有了,感謝大佬
!

1、MySQL的修仙之路,圖文談談如何學MySQL、如何進階!
2、數(shù)據(jù)庫面經(jīng),常見的面試題
5、對Not Null字段插入Null值有啥現(xiàn)象?
6、能談談year、date、datetime、time、timestamp的區(qū)別嗎?
8、你知道數(shù)據(jù)庫緩沖池中的LRU-List嗎?
10、了解Flush-List嗎?順便說一下臟頁的落盤機制!
11、用 11 張圖講清楚,當你CRUD時BufferPool中發(fā)生了什么!以及BufferPool的優(yōu)化!
12、了解 MySQL的表空間?和?數(shù)據(jù)表嗎?談談看!
13、了解 MySQL的數(shù)據(jù)行嗎?行溢出機制呢?談談看!
14、了解MySQL數(shù)據(jù)頁嗎?說說什么是頁分裂吧!
16、簡述undo log、truncate、以及undo log如何幫你回滾事務?
19、LSN、Checkpoint?談談MYSQL的崩潰恢復是怎么回事!
20、MySQL的 bin log有啥用?在哪里?誰寫的?怎么配置?
21、bin log有哪些格式?有啥區(qū)別?優(yōu)缺點?線上用哪種格式?
23、全網(wǎng)最牛X的!MySQL兩階段提交串講!沒有之一!
24、自導自演的數(shù)據(jù)庫面試現(xiàn)場--談談MySQL的10種文件
25、大型面試現(xiàn)場:一條update sql的執(zhí)行都經(jīng)歷了什么?
歡迎加入白日夢的圈子、一起吃肉!
長按二維碼、關注白日夢
贈送精美腦圖
(操作系統(tǒng)、網(wǎng)絡、Java基礎...)
長按二維碼
關注白日夢吧!
