簡要說明:java
表設計時,須要往表裏加一個version字段。每次查詢時,查出帶有version的數據記錄,更新數據時,判斷數據庫裏對應id的記錄的version是否和查出的version相同。若相同,則更新數據並把版本號+1;若不一樣,則說明,該數據發送併發,被別的線程使用了,進行遞歸操做,再次執行遞歸方法,知道成功更新數據爲止python
簡單說說樂觀鎖。樂觀鎖是相對於悲觀鎖而言。悲觀鎖認爲,這個線程,發生併發的可能性極大,線程衝突概率大,比較悲觀。通常用synchronized實現,保證每次操做數據不會衝突。樂觀鎖認爲,線程衝突可能性小,比較樂觀,直接去操做數據,若是發現數據已經被更改(經過版本號控制),則不更新數據,再次去重複 所需操做,知道沒有衝突(使用遞歸算法)。算法
由於樂觀鎖使用遞歸+版本號控制 實現,因此,若是線程衝突概率大,使用樂觀鎖會重複不少次操做(包括查詢數據庫),尤爲是遞歸部分邏輯複雜,耗時和耗性能,是低效不合適的,應考慮使用悲觀鎖。數據庫
樂觀鎖悲觀鎖的選擇:併發
樂觀鎖:併發衝突概率小,對應模塊遞歸操做簡單 時使用app
悲觀鎖:併發概率大,對應模塊操做複雜 時使用性能
案例一學習
/** * 自動派單 * 只查出一條 返回list只是爲了和查詢接口統一 * 視頻審覈訂單不派送 * @param paramMap * @return */ public List<AutomaticAssignDto> automaticAssign(Map<String, Object> paramMap){ //派送規則 String changeSortSet = RedisCacheUtil.getValue(CACHE_TYPE.APP, "changeSortSet"); if (StringUtils.isBlank(changeSortSet)) { changeSortSet = customerManager.getDictionaryByCode("changeSortSet"); if (StringUtils.isNotBlank(changeSortSet)) { RedisCacheUtil.addValue(CACHE_TYPE.APP, "changeSortSet", changeSortSet,30,TimeUnit.DAYS); } else { changeSortSet = ConstantsUtil.AssignRule.FIFO; // 默認先進先審 } } AutomaticAssignDto automaticAssignDto = new AutomaticAssignDto(); automaticAssignDto.setChangeSortSet(changeSortSet); automaticAssignDto.setUserTeam(CommonUtils.getValue(paramMap, "userTeam")); List<AutomaticAssignDto> waitCheckList = automaticAssignMybatisDao.automaticAssignOrder(automaticAssignDto); if(waitCheckList != null && waitCheckList.size()>0){ automaticAssignDto = waitCheckList.get(0); automaticAssignDto.setSendStatus(ConstantsUtil.SendStatus.SEND); automaticAssignDto.setBindTime(new Date()); automaticAssignDto.setUserId(Long.parseLong(paramMap.get("userId").toString()) ); int sum = automaticAssignMybatisDao.bindAutomaticAssignInfo(automaticAssignDto); if(sum == 1){ return waitCheckList; }else{ //已被更新 則再次獲取 return automaticAssign(paramMap); } }else{ return null; } }
學習自 https://blog.csdn.net/zhangdehua678/article/details/79594212ui
案例二this
package what21.thread.lock; public class OptimLockMain { // 文件版本號 static int version = 1; // 操做文件 static String file = "d://IT小奮鬥.txt"; /** * 獲取版本號 * * @return */ public static int getVersion(){ return version; } /** * 更新版本號 */ public static void updateVersion(){ version+=1; } /** * @param args */ public static void main(String[] args) { for(int i=1;i<=5;i++){ new OptimThread(String.valueOf(i),getVersion(),file).start(); } } } package what21.thread.lock; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class OptimThread extends Thread { // 文件版本號 public int version; // 文件 public String file; public OptimThread(String name,int version,String file){ this.setName(name); this.version = version; this.file = file; } public void run() { // 1. 讀取文件 String text = read(file); println("線程"+ getName() + ",文件版本號爲:" + OptimLockMain.getVersion()); println("線程"+ getName() + ",版本號爲:" + getVersion()); // 2. 寫入文件 if(OptimLockMain.getVersion() == getVersion()){ println("線程" + getName() + ",版本號爲:" + version + ",正在執行"); // 文件操做,這裏用synchronized就至關於文件鎖 // 若是是數據庫,至關於表鎖或者行鎖 synchronized(OptimThread.class){ if(OptimLockMain.getVersion() == this.version){ // 寫入操做 write(file, text); // 更新文件版本號 OptimLockMain.updateVersion(); return ; } } } // 3. 版本號不正確的線程,須要從新讀取,從新執行 println("線程"+ getName() + ",文件版本號爲:" + OptimLockMain.getVersion()); println("線程"+ getName() + ",版本號爲:" + getVersion()); System.err.println("線程"+ getName() + ",須要從新執行。"); } /** * @return */ private int getVersion(){ return this.version; } /** * 寫入數據 * * @param file * @param text */ public static void write(String file,String text){ try { FileWriter fw = new FileWriter(file,false); fw.write(text + "\r\n"); fw.flush(); fw.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 讀取數據 * * @param file * @return */ public static String read(String file){ StringBuilder sb = new StringBuilder(); try { File rFile = new File(file); if(!rFile.exists()){ rFile.createNewFile(); } FileReader fr = new FileReader(rFile); BufferedReader br = new BufferedReader(fr); String r = null; while((r=br.readLine())!=null){ sb.append(r).append("\r\n"); } br.close(); fr.close(); } catch (IOException e) { e.printStackTrace(); } return sb.toString(); } /** * @param content */ public static void println(String content){ System.out.println(content); } }
學習自https://blog.csdn.net/qq897958555/article/details/79337064