背景描述
應用框架:Spring Boot + mybatis
數據庫:Sqlserver
系統一個業務號只允許存在一筆正在處理的預約訂單,當多個用戶同時發送多筆業務號相同的預約訂單,我們發現數據庫中也會存在多筆業務號相同的預約訂單。。按照程序的編寫邏輯,重複的數據應當是會被判斷出來不被存儲的。
1.原因分析
由於短時間內客戶可能連續推送了兩條重複的數據,兩條數據時間間隔非常小,因此導致了我們的
if(業務號存在){
// ...
}
否則訂單入庫
if 裏面操作還沒有執行完畢,第二條擁有相同數據的線程已經進入並通過了if的檢驗,導致數據庫存儲了兩條相同的數據。
2.解決方法
(1)使用synchronized同步代碼塊即加同步鎖
synchronized(this){
//...
}
這樣會導致其他正常數據的推送線程也被阻塞,影響效率。因此不採用。我們考慮只對重複數據加鎖。
String lonNbr=... ;
synchronized(lonNbr.intern()) {
//...
}
使用String作爲同步鎖必須注意產生不同對象的問題,必須保證線程拿到的是同一個String對象,但這個有時很難保證。這個時候就得使用intern()方法,這樣就是直接獲取的是字符串的值本身,而不是取的String的對象。
Java中String做爲synchronized同步鎖使用詳解
這種加同步鎖的方法在負載均衡下的多臺應用服務器會失效!
(2)分佈式鎖
基於數據庫實現分佈式鎖;(唯一索引,事務隔離級別,鎖)
基於緩存(Redis等)實現分佈式鎖;
基於Zookeeper實現分佈式鎖;