當(dāng)我們與數(shù)據(jù)庫打交道時,并發(fā)是經(jīng)常要進行處理的,同時對一條記錄進行讀取并更新時,雖有先后順序,但就如同我們審核任務(wù)一樣,幾個人拿到同一個任務(wù),同時評分1分2分3分,最終這個任務(wù)的分?jǐn)?shù)是由最后提交的給更新了。當(dāng)更新完畢,再次拿到打分時,會校驗已經(jīng)打過分了,不允許評分。問題就出現(xiàn)在同時更新時。
數(shù)據(jù)庫事務(wù)的隔離級別有4個,由低到高依次為Read uncommitted、Read committed、Repeatable read、Serializable,這四個級別可以逐個解決臟讀、不可重復(fù)讀、幻讀這幾類問題。
Read uncommitted:讀未提交的數(shù)據(jù)
Read committed: 讀提交
Repeatable read:不可重復(fù)讀
Serializable: 序列化
大多數(shù)據(jù)庫使用Read committed,這是性能和安全的結(jié)合點,并使用加鎖的方式來解決安全問題。
解決此類問題有悲觀鎖和樂觀鎖兩種方式,
悲觀鎖:A查詢出這條任務(wù)時就會拿到一把鎖,這把鎖是更新鎖,其他人依然可以查出這條任務(wù),但是在A更新之前的過程中,后查詢出任務(wù)的BCD等不可以進行更新,更新就會報錯。
樂觀鎖:A查詢出這條任務(wù)時,拿到這條任務(wù)的一個版本號version,沒更新一次version++,當(dāng)A進行更新時,一旦發(fā)現(xiàn)數(shù)據(jù)庫版本和自己拿到的版本不對,就報錯,否則正常更新。
例子:
悲觀鎖:LockMode.UPGRADE實現(xiàn)加鎖
Task a = (Task)session.load(Task.class, 1, LockMode.UPGRADE);
樂觀鎖:在需要加鎖的類里加一個version字段,注解@Version
private int version;
@Version
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
常用的是樂觀鎖,悲觀鎖效率太低,一旦有人拿到任務(wù)不進行更新,那就意味著所有人都會受影響。