最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2016年03月04日 17:06:10   投稿:lijiao  
這篇文章主要介紹了并發(fā)環(huán)境下mysql插入檢查方案的相關(guān)資料,需要的朋友可以參考下

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

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

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

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

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

public static void StartTransaction(Connection con, String[] sqls) throws Exception { 
    try { 
      // 事務(wù)開(kāi)始 
      con.setAutoCommit(false);  // 設(shè)置連接不自動(dòng)提交,即用該連接進(jìn)行的操作都不更新到數(shù)據(jù)庫(kù) 
      sm = con.createStatement(); // 創(chuàng)建Statement對(duì)象 

      //依次執(zhí)行傳入的SQL語(yǔ)句 
      for (int i = 0; i < sqls.length; i++) { 
        sm.execute(sqls[i]);// 執(zhí)行添加事物的語(yǔ)句 
      } 
      con.commit();  // 提交給數(shù)據(jù)庫(kù)處理 
      // 事務(wù)結(jié)束 

    //捕獲執(zhí)行SQL語(yǔ)句組中的異常   
    } catch (SQLException e) { 
      try { 
        System.out.println("事務(wù)執(zhí)行失敗,進(jìn)行回滾!\n"); 
        con.rollback(); // 若前面某條語(yǔ)句出現(xiàn)異常時(shí),進(jìn)行回滾,取消前面執(zhí)行的所有操作 
      } catch (SQLException e1) { 
        e1.printStackTrace(); 
      } 
    } finally { 
      sm.close(); 
    } 
  }

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

既然sql層面沒(méi)有解決問(wèn)題,就考慮從java的并發(fā)編程方向解決。
解決方案三:
java解決并發(fā)問(wèn)題,首先想到的是使用內(nèi)置鎖或者可重入鎖,基本語(yǔ)法如下:
·內(nèi)置鎖:
由于是在Servlet中進(jìn)行的處理,因此使用synchronized(this)直接處理業(yè)務(wù)代碼,使得并發(fā)情況下,只能有一個(gè)線程訪問(wèn)到該段業(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)過(guò)測(cè)試,這個(gè)方案是可行的,最終沒(méi)有采用的原因是因?yàn)橹苯邮褂眠@種方式加鎖,加鎖的代碼太多,影響效率。

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

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

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

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

相關(guān)文章

最新評(píng)論

曲周县| 大同市| 阿巴嘎旗| 赞皇县| 平舆县| 固镇县| 化州市| 彭泽县| 固始县| 梁山县| 普陀区| 北宁市| 建平县| 乌拉特中旗| 康乐县| 平南县| 新野县| 泰兴市| 滦平县| 乌拉特中旗| 柳河县| 东光县| 青铜峡市| 治县。| 江西省| 上虞市| 南开区| 蒙自县| 东兰县| 二连浩特市| 伊宁县| 庆城县| 玛纳斯县| 盘山县| 阿克陶县| 麻阳| 汾西县| 澄城县| 九江市| 云南省| 德兴市|