国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數(shù)據(jù)庫 > MySQL > 正文

并發(fā)環(huán)境下mysql插入檢查方案

2024-07-24 13:08:52
字體:
供稿:網(wǎng)友
這篇文章主要介紹了并發(fā)環(huán)境下mysql插入檢查方案的相關(guān)資料,需要的朋友可以參考下
 

業(yè)務(wù)背景: 
基本業(yè)務(wù)場景是這樣的,請求數(shù)據(jù)(車輛vin信息)進(jìn)入到接口中,需要先判斷其在數(shù)據(jù)庫中的狀態(tài),如果庫中不存在該vin,或者該vin狀態(tài)位為“1(已完成)”,則執(zhí)行一些檢查操作后,將數(shù)據(jù)插入到數(shù)據(jù)庫中,此時新增vin狀態(tài)為0,調(diào)用人工處理接口,十分鐘后返回結(jié)果,將狀態(tài)置為1。如果其狀態(tài)位為“0(正在處理)”則駁回操作,返回提示信息。 
在單線程環(huán)境下,這樣的業(yè)務(wù)沒有問題,然而當(dāng)并發(fā)訪問接口時,會出現(xiàn)同時進(jìn)入兩條vin相同的請求AB,正常情況應(yīng)該插入一條A,駁回一條B。然而并發(fā)環(huán)境下,B執(zhí)行檢查狀態(tài)時A還沒有插入,因此AB都進(jìn)入到了數(shù)據(jù)庫中,數(shù)據(jù)就錯誤了。

解決方案一: 
首先想到的是使用sql處理,對數(shù)據(jù)庫對應(yīng)字段加唯一索引,保證一致性。如果插入重復(fù)的數(shù)據(jù),則catch該異常,做出提示。

ALTER tableName ADD UNIQUE [indexName] ON (tableColumns(length))

但是由于業(yè)務(wù)限制,vin在庫中是可以重復(fù)的,多條重復(fù)數(shù)據(jù)查詢最新,所以不能再vin上添加唯一索引。

解決方案二: 
使用mysql事務(wù)操作,將檢查是否存在和插入作為一個事務(wù)進(jìn)行處理,當(dāng)檢查失敗的時候,不進(jìn)行插入。從網(wǎng)上搜索了一下,大致思路如下:

 

public static void StartTransaction(Connection con, String[] sqls) throws Exception {     try {       // 事務(wù)開始       con.setAutoCommit(false);  // 設(shè)置連接不自動提交,即用該連接進(jìn)行的操作都不更新到數(shù)據(jù)庫       sm = con.createStatement(); // 創(chuàng)建Statement對象       //依次執(zhí)行傳入的SQL語句       for (int i = 0; i < sqls.length; i++) {         sm.execute(sqls[i]);// 執(zhí)行添加事物的語句       }       con.commit();  // 提交給數(shù)據(jù)庫處理       // 事務(wù)結(jié)束     //捕獲執(zhí)行SQL語句組中的異常       } catch (SQLException e) {       try {         System.out.println("事務(wù)執(zhí)行失敗,進(jìn)行回滾!/n");         con.rollback(); // 若前面某條語句出現(xiàn)異常時,進(jìn)行回滾,取消前面執(zhí)行的所有操作       } catch (SQLException e1) {         e1.printStackTrace();       }     } finally {       sm.close();     }   }

但是這樣實際上還是沒有解決并發(fā)的問題,這樣只是把兩個操作變成了一個原子的sql操作,可以用于同時插入兩條數(shù)據(jù)一致性的情況,但并不適合需求。

既然sql層面沒有解決問題,就考慮從java的并發(fā)編程方向解決。 
解決方案三: 
java解決并發(fā)問題,首先想到的是使用內(nèi)置鎖或者可重入鎖,基本語法如下: 
·內(nèi)置鎖: 
由于是在Servlet中進(jìn)行的處理,因此使用synchronized(this)直接處理業(yè)務(wù)代碼,使得并發(fā)情況下,只能有一個線程訪問到該段業(yè)務(wù)代碼:

synchronized(this){  //todo1:檢查vin是否存在  //todo2:如果不存在插入vin}

·可重入鎖: 
相當(dāng)于更靈活的內(nèi)置鎖,在這里與內(nèi)置鎖基本相同

public class DashengCallBack extends HttpServlet {  private static ReentrantLock lock= new ReentrantLock();  protected void doGet(HttpServletRequest request, HttpServletResponse response){    lock.lock();    try{      //todo1:檢查vin是否存在      //todo2:如果不存在插入vin    }finally{      lock.unlock();    }  }}

經(jīng)過測試,這個方案是可行的,最終沒有采用的原因是因為直接使用這種方式加鎖,加鎖的代碼太多,影響效率。

解決方案四: 
設(shè)置一個查詢Map,插入前存儲數(shù)據(jù),插入后刪除數(shù)據(jù),代碼如下:

    ConcurrentHashMap<String, String> vinMap=new ConcurrentHashMap<String,String>();    if(vinMap.containsKey(vin)){      // todo1: vin 請求完畢后, 從vinInRequestMap里刪掉這個vinNo      // todo2: 返回正在查詢    }    vinMap.put(vin, "");    //todo3:插入vin到數(shù)據(jù)庫    vinMap.remove(vin);  }

這個方案基本滿足了業(yè)務(wù)需求,唯一的問題是要求接口的更新時間要與業(yè)務(wù)時間錯開,否則更新接口會清空vinMap,導(dǎo)致庫中數(shù)據(jù)混亂,出現(xiàn)錯誤。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。



注:相關(guān)教程知識閱讀請移步到MYSQL教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 七台河市| 阿合奇县| 嘉峪关市| 宜丰县| 获嘉县| 会泽县| 卢氏县| 铁力市| 阿图什市| 社旗县| 凤翔县| 汾阳市| 南汇区| 明溪县| 玉环县| 灵宝市| 沈阳市| 关岭| 清徐县| 宽城| 阿坝县| 东阿县| 红河县| 锡林浩特市| 平凉市| 益阳市| 石林| 青龙| 大姚县| 眉山市| 永仁县| 丹江口市| 江门市| 铜山县| 米泉市| 枣阳市| 兴安县| 巩留县| 吴忠市| 镇沅| 丁青县|