1. 程式人生 > >JPA使用樂觀鎖應對高併發

JPA使用樂觀鎖應對高併發

高併發系統的挑戰

在部署分散式系統時,我們通常把多個微服務部署在內網叢集中,再用API閘道器聚合起來對外提供。為了做負載均衡,通常會對每個微服務都啟動多個執行例項,通過註冊中心去呼叫。

那麼問題來了,因為有多個例項執行都是同一個應用,雖然微服務閘道器會把每一個請求只轉發給一個例項,但當面對高併發時,但它們仍然可能同時操作同一個資料庫表,這會不會引發什麼問題呢?

悲觀鎖的問題

比如電商中常見的商品秒殺系統,在使用者搶購商品過程中,會有大量併發請求,很可能同時讀寫一個包含商品剩餘數量的表,這種一般要給資料庫加鎖,否則很容易出現商品超賣錯賣的情況。

如果使用資料庫自帶的鎖機制,也就是悲觀鎖,在寫入的時候鎖定資料庫,其他修改請求到來時就必須等待鎖釋放,但這就使效率降下來了,而且高併發場景下可能有的請求一直搶不到鎖,就會長時間卡在那導致請求失敗,然後有大量重試,系統可能會發生連線數耗盡等異常。

樂觀鎖是個好東西

查閱資料發現樂觀鎖是個好東西,它是為資料庫表增加一個標識資料版本的version欄位來實現的,讀取資料時把version欄位一同讀出,寫入資料庫時比對version欄位就知道資料是否被更改過,如果version不相等就說明持有的是過期資料,不能寫入,如果相等就可以寫入,並把version加一。

樂觀鎖在寫入資料庫的時候,才會檢查資料是否衝突,如果發現衝突了,就放棄寫入,返回寫入失敗的資訊,相比於悲觀鎖,這是一種輕量級的對資料的鎖定方式,能夠應對高併發需求。

給資料庫新增樂觀鎖

說樂觀鎖是個好東西,首先得說 JPA 是個好東西,因為Spring Data JPA已經內建了樂觀鎖的實現,給資料庫表新增樂觀鎖很簡單,新增一個整型欄位,並加入@Version註解就可以了,每次提交資料時JPA會自動檢查版本。

    @Entity  
    @Table(name = "m_order")  
    public class Order {  
    ...  
        @Version  
        private int version;  
    ...  
    }  

掃一掃關注我的微信公眾號

掃一掃關注我的微信公眾號