您好,登錄后才能下訂單哦!
小編給大家分享一下MySQL中使用if not exists需要注意什么,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!
環(huán)境MySQL 5.6.14
事務隔離級別 讀提交
事務的開啟和結束由JAVA程序控制.
上次報死鎖的過程,抽象如下
delimitr $$
CREATE PROCEDURE `test_proc`(
pid int
)
begin
if not exists (select * from t where id=pid) then
insert into t(id) values(pid);
end if;
update t set total=total+1 where id=pid;
end $$
delimiter ;
死鎖原因已經(jīng)明白了,就是并發(fā)情況下,Insert遇到排它鎖,則嘗試加共享鎖。
在最后Update的時候,兩個持有共享鎖的連接,都嘗試申請排它鎖,則導致了死鎖.
但是問題是...怎么會走到了最后一行的Update語句?
另外兩個連接,不是應該在Insert語句時報 Duplicate entry 'xx' for key 'PRIMARY'錯誤嗎?
問題應該出在這種結構里
if not exists (select * from t where id=pid) then
xxx
end if;
使用 if not exists 模式,真心要注意啊.在這種結構里出現(xiàn)的異常,不會報錯,而是直接跳出IF判斷,繼續(xù)執(zhí)行??!
實驗準備
CREATE TABLE `t` (
`id` int(11) NOT NULL,
`total` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
truncate table t;
drop procedure if exists test_proc;
delimiter $$
CREATE PROCEDURE `test_proc`(
pid int,
ptotal int
)
begin
if not exists (select * from t where id=pid) then
insert into t(id,total) value(pid,ptotal);
update t set total=ptotal+1 where id=pid;
end if;
select ptotal+1;
end $$
delimiter ;
打開三個客戶端,分別執(zhí)行過程
第一個客戶端執(zhí)行,并沒有提交.
第二,第三客戶端處于阻塞狀態(tài).
等第一個客戶端提交,
第二個客戶端返回 201
第三個客戶端返回 301
且沒有任何的報錯信息.
三個客戶端都提交之后,查看T表信息
只有一個記錄,id為1,total為101
也就是說,第二個,第三個客戶端,在得到主鍵沖突的異常后,沒有報錯,沒有繼續(xù)執(zhí)行IF塊內(nèi)剩下的語句,而是直接跳出了IF塊,繼續(xù)執(zhí)行IF塊外的語句!!
該報錯的地方不報錯,在大段的存儲過程中,導致死鎖還是小問題,就怕引起數(shù)據(jù)的錯亂,而不自知.
針對這種情況,如果有主鍵或者唯一約束,我覺得干脆改為如下的方式.
delimiter $$
CREATE PROCEDURE `test_proc`(
pid int,
ptotal int
)
begin
insert into t(id,total) value(pid,ptotal);
update t set total=ptotal+1 where id=pid;
select ptotal+1;
end $$
delimiter ;
看完了這篇文章,相信你對“MySQL中使用if not exists需要注意什么”有了一定的了解,如果想了解更多相關知識,歡迎關注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。