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