介紹
最近接觸了分布式事務(wù)蒙幻,二階段鎖定映凳、2pc胆筒、數(shù)據(jù)庫相關(guān)知識(事務(wù)隔離邮破、日志等)有點懵懂。
忽然想到高并發(fā)業(yè)務(wù)場景(例如搶票仆救、電商之類的)抒和,多線程出現(xiàn)超出剩余票數(shù)或庫存,超賣的情形是如何解決的彤蔽。
一個簡單的模型
public boolean product(Long producId) {
Product product = SELECT * FROM TABLE WHERE producId = xxx;
if (product.getNum() > 0) {
int updateRow = UPDATE TABLE SET num = product.getNum() - 1 WHERE producId = xxx;
if(updateRow>0){
return true; //更新成功
}
}
return false;
}
select查詢該商品摧莽,若有剩余商品,則進行-1更新操作顿痪,不出現(xiàn)并發(fā)的情形就不會出錯镊辕。
如果多線程的話,會出現(xiàn)更新丟失的情況蚁袭,假設(shè)庫存現(xiàn)在為1征懈,一個事務(wù)發(fā)現(xiàn)人
網(wǎng)上查閱后,一些解決辦法:
悲觀鎖揩悄、樂觀鎖
悲觀鎖
每次拿到數(shù)據(jù)都認為會更新(悲觀)卖哎,于是每次拿數(shù)據(jù)則上鎖。
java的synchronized就是悲觀鎖的一種實現(xiàn)删性。
InnoDB在讀取行時有兩種行鎖:讀共享鎖和寫?yīng)氄兼i亏娜。
讀共享鎖:SELECT * FROM TABLE WHERE producId = xxx LOCK IN SHARE MODE;
如果事務(wù)A先獲得了讀共享鎖,那么事務(wù)B之后仍然可以讀取加了讀共享鎖的行數(shù)據(jù)蹬挺,但必須等事務(wù)A commit或者roll back之后才可以更新或者刪除加了讀共享鎖的行數(shù)據(jù)维贺。
寫?yīng)氄兼i:SELECT * FROM TABLE WHERE producId = xxx LOCK FOR UPDATE;
如果事務(wù)A先獲得了某行的寫共享鎖,那么事務(wù)B就必須等待事務(wù)A commit或者roll back之后才可以訪問行數(shù)據(jù)巴帮。
這里需要寫?yīng)氄兼i
public boolean product(Long producId) {
Product product = SELECT * FROM TABLE WHERE producId = xxx LOCK FOR UPDATE;
if (product.getNum() > 0) {
int updateRow = UPDATE TABLE SET num = product.getNum() - 1 WHERE producId = xxx;
if(updateRow>0){
return true; //更新成功
}
}
return false;
}
樂觀鎖
顧名思議溯泣,每次讀取數(shù)據(jù)都不認為別人會進行修改群发,所以不會上鎖,但是會在更新提交的時候判斷下在此期間是否有更新
public boolean product(Long producId) {
int updateRow = 0;
while (updateRow == 0) {
Product product = SELECT * FROM TABLE WHERE producId = xxx;
if (product.getNum() > 0) {
updateRow = UPDATE TABLE SET num = product.getNum() - 1 WHERE producId = xxx AND num = product.getNum();
if (updateRow > 0) {
return true; //更新成功
}
}else{
return false;
}
}
return false;
}
通過在UPDATE操作加上限定num = product.getNum()
,如果num和通過查找SELECT操作得到的num不一致发乔,說明事務(wù)并發(fā)有所影響熟妓,此時業(yè)務(wù)需要回滾或者重新執(zhí)行。
Q:
- UPDATE的行鎖問題栏尚?
- commit之前有所誤解起愈,事務(wù)提交和數(shù)據(jù)寫入有所弄混(redo、undo译仗、寫入磁盤等)
- 由上述問題引發(fā)事務(wù)隔離與鎖的問題
- 二階段鎖定和那些事務(wù)執(zhí)行中的鎖 概念有所弄混