理解 悲觀鎖就是什麼事情都是須要當心翼翼,生怕弄錯了出大問題,git
通常狀況下 "增刪改" 都是有事務在進行操做的,可是 "查" 是不須要事務操做的,sql
可是凡事沒有例外,好比雙十一購物,不少人搶購一個物品,可是商品總數(假設5個)數據庫
同一時間進行操做,每一個人都能看到物品多少個,都早同一時間下單,可是隻有5個商品,只有5個用戶能過購買到(每人一個購買),其餘人也會顯示出訂單的操做,可是庫存已是爲0沒法購買的行爲(顯示仍是5ge庫存),會給用戶形成很差體驗安全
既讓如此 爲何不讓一個事務鎖定物品的個數修改,而其餘用戶只能查看,並不能下單,當用戶進行updata操做以後釋放鎖,其餘用戶才能根據狀況下單,再次把物品行鎖住(不會出現訂單表交錢了還提示沒庫存)spa
可能我說的不是很準確,可是悲觀鎖就是一步一步走,若是輪到它則執行則鎖行操做,避免一些問題,通常用在金錢查詢,庫存查詢等... 版本控制
執行sql語句格式code
select money from usercred where id=1 for update;
統一格式在select查詢條件以後增長 for updata (記住查詢條件是索引列纔是鎖行不讓則是鎖表) 查詢操做中除了敏感數據查詢,其餘不須要使用鎖行操做orm
整體理解就是 悲觀鎖是一個在有須要求的狀況下查詢語句事務中隔離性最高的ser... 串行,當悲觀鎖鎖住行時,其餘事務只能等待,而且不能讀取該行悲觀數據blog
而且悲觀鎖只能在begin和commit之間執行索引
樂觀鎖 查詢出須要修改的數據,可是增長一個字段做爲一個版本控制(像git同樣),若是進行修改一塊兒將版本控制的字段一塊兒where做爲條件,若是符合則修改,不符合也沒事,由於數據庫中的數據給其餘事務修改以後,where查詢的條件不符合,因此不會對持久化的數據形成影響
例子以下
create table card( id int; money float; version int; // 樂觀鎖控制,字段名無所謂 primary key(id); // 主鍵 auto increment(id); // 自增加 index(money,version); // 索引 );
建立上面一個表,我使用go的gorm來表達一下操做
type card struct{ Id int `gorm:"id"` Money float `gorm:"money"` // 默認這個帳戶100元 Version int `gorm:"varsion"` } func main(){ var c card if err := db.first(&c).Error():err!=nil{ // 查出一條數據 panic(err) } err = db.Model(&c).Where("id = ? and varsion = ?",c.Id,c.Version).updata(c.Money + 200 ,c.Version+1).error() if err != nil{ // 說明其餘事務在我執行這個操做時進行了updata commit,我這邊where在數據查詢表沒有出現符合條件的,因此執行失敗 } fmt.Println("success") }
樂觀鎖就不是一個事務的操做,是手動建立的一種邏輯來保證數據一致性
根據多個條件來進行控制數據是否和查詢時一致保持安全
比方 a 操做查詢獲得一個數據,其中返回的數據集中含有 money(100)和一個varsion(1),,你對這個數據進行修改,其中money+100,varsion+1 ,可是在你修改尚未提交時,其餘b,c,d..的鏈接也同時和你同樣的操做,而且比你提交commit的速度快,當你使用updata修改語句去根據先前查詢獲得結果尋找數據時,對比version和money,可是已經有其餘提交比你快提交了,找不到a查詢過的數據行(此時時b鏈接提交的數據是money = 300,version=2),因此不會提交,丟棄操做,
樂觀使用一個額外字段保證數據和查詢出時的數據一致纔會更新(更新查詢時查詢的條件要有惟一屬性,不讓更新查詢時出現多個操做不可逆)
悲觀鎖更加適合轉帳交易業務,樂觀鎖傾向並非對數據要求絕對安全的環境,可是絕對不適用於轉帳交易等敏感地位
悲觀鎖和事務區別在於
悲觀鎖會將查詢時就將行鎖住,其餘鏈接操做不能查詢更不能修改,可是也是事務的一種
事務 通常用於增刪改而不用於查的事務管理(雖然也能夠管理查的事務,可是和悲觀鎖同樣差很少,除非時特別需求,否則不會要求對查的操做加鎖)