亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

MongoDB中ObjectId的誤區(qū)及引起的一系列問(wèn)題

 更新時(shí)間:2016年12月25日 16:59:51   作者:大齊NJ  
這篇文章主要介紹了MongoDB中ObjectId的誤區(qū)及引起的一系列問(wèn)題,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下

近期對(duì)兩個(gè)應(yīng)用進(jìn)行改造,在上線過(guò)程中出現(xiàn)一系列問(wèn)題(其中一部分是由于ObjectId誤區(qū)導(dǎo)致的)

先來(lái)了解下ObjectId:

TimeStamp

前 4位是一個(gè)unix的時(shí)間戳,是一個(gè)int類(lèi)別,我們將上面的例子中的objectid的前4位進(jìn)行提取“4df2dcec”,然后再將他們安裝十六進(jìn)制 專(zhuān)為十進(jìn)制:“1307761900”,這個(gè)數(shù)字就是一個(gè)時(shí)間戳,為了讓效果更佳明顯,我們將這個(gè)時(shí)間戳轉(zhuǎn)換成我們習(xí)慣的時(shí)間格式(精確到秒)

$ date -d '1970-01-01 UTC 1307761900 sec' -u

2011年 06月 11日 星期六 03:11:40 UTC

前 4個(gè)字節(jié)其實(shí)隱藏了文檔創(chuàng)建的時(shí)間,并且時(shí)間戳處在于字符的最前面,這就意味著ObjectId大致會(huì)按照插入進(jìn)行排序,這對(duì)于某些方面起到很大作用,如 作為索引提高搜索效率等等。使用時(shí)間戳還有一個(gè)好處是,某些客戶端驅(qū)動(dòng)可以通過(guò)ObjectId解析出該記錄是何時(shí)插入的,這也解答了我們平時(shí)快速連續(xù)創(chuàng) 建多個(gè)Objectid時(shí),會(huì)發(fā)現(xiàn)前幾位數(shù)字很少發(fā)現(xiàn)變化的現(xiàn)實(shí),因?yàn)槭褂玫氖钱?dāng)前時(shí)間,很多用戶擔(dān)心要對(duì)服務(wù)器進(jìn)行時(shí)間同步,其實(shí)這個(gè)時(shí)間戳的真實(shí)值并 不重要,只要其總不停增加就好。

Machine

接下來(lái)的三個(gè)字節(jié),就是 2cdcd2 ,這三個(gè)字節(jié)是所在主機(jī)的唯一標(biāo)識(shí)符,一般是機(jī)器主機(jī)名的散列值,這樣就確保了不同主機(jī)生成不同的機(jī)器hash值,確保在分布式中不造成沖突,這也就是在同一臺(tái)機(jī)器生成的objectid中間的字符串都是一模一樣的原因。

pid

上面的Machine是為了確保在不同機(jī)器產(chǎn)生的objectid不沖突,而pid就是為了在同一臺(tái)機(jī)器不同的mongodb進(jìn)程產(chǎn)生了objectid不沖突,接下來(lái)的0936兩位就是產(chǎn)生objectid的進(jìn)程標(biāo)識(shí)符。

increment

前面的九個(gè)字節(jié)是保證了一秒內(nèi)不同機(jī)器不同進(jìn)程生成objectid不沖突,這后面的三個(gè)字節(jié)a8b817,是一個(gè)自動(dòng)增加的計(jì)數(shù)器,用來(lái)確保在同一秒內(nèi)產(chǎn)生的objectid也不會(huì)發(fā)現(xiàn)沖突,允許256的3次方等于16777216條記錄的唯一性。

ObjectId唯一性

大家可能會(huì)覺(jué)得,在某種程度上已經(jīng)可以保證唯一了,不管在客戶端還是在服務(wù)端。

誤區(qū) 一 、文檔順序和插入順序一致?

單線程情況

ObjectId中的timestamp、machine、pid、inc都可以保證唯一,因?yàn)樵谕慌_(tái)機(jī)器,同一個(gè)進(jìn)程。

這里有一個(gè)問(wèn)題,mongodb的操作時(shí)多線程的。a、b、c...幾個(gè)線程進(jìn)行入庫(kù)操作時(shí),不能保證哪一條可以在另外一條之前,所以會(huì)是亂序的。

多線程、多機(jī)器或多進(jìn)程情況

再看下ObjectId中mache、pid不能保證唯一。那么則數(shù)據(jù)更加會(huì)是亂序的。

解決辦法:

由于collection集合中數(shù)據(jù)是無(wú)序的(包括capped collection),那么,最簡(jiǎn)單的辦法是對(duì)ObjectId進(jìn)行排序。

可以使用兩種方法排序,

1.mongoDB查詢語(yǔ)句

jQuery query = new Query(); 
if (id != null) 
{ 
  jquery.addCriteria(Criteria.where("_id").gt(id)); 
} 
jquery.with(new Sort(Sort.Direction.ASC, "_id")); 

2.java.util.PriorityQueue

Comparator<DBObject> comparator = new Comparator<DBObject>() 
{ 
  @Override 
  public int compare(DBObject o1, DBObject o2) 
  { 
    return ((ObjectId)o1.get("_id")).compareTo((ObjectId)o2.get("_id")); 
  } 
}; 
PriorityQueue<DBObject> queue = new PriorityQueue<DBObject>(200,comparator); 

誤區(qū) 二 、多客戶端高并發(fā)時(shí),是否可以保證順序(sort之后)?

如果一直保證寫(xiě)入遠(yuǎn)遠(yuǎn)大于讀出(間隔一秒以上),這樣是永遠(yuǎn)不會(huì)出現(xiàn)亂序的情況。

我們來(lái)看下樣例

現(xiàn)在看到圖中,取出數(shù)據(jù)兩次

第一次

4df2dcec aaaa  ffff 36a8b813
4df2dcec aaaa  eeee 36a8b813
4df2dcec bbbb  1111 36a8b814

第二次

4df2dcec bbbb  1111 36a8b813
4df2dcec aaaa  ffff 36a8b814
4df2dcec aaaa  eeee 36a8b814

現(xiàn)在如果取第一次的最大值(4df2dcec bbbb  1111 36a8b814)做下次查詢的結(jié)果,那么就會(huì)漏掉

第二次的三條,因?yàn)椋?df2dcec bbbb  1111 36a8b814)大于第二次取的所有記錄。

所以會(huì)導(dǎo)致丟數(shù)據(jù)的情況。

解決辦法:

由于ObjectId的時(shí)間戳截止到秒,而counter算子前四位又為機(jī)器與進(jìn)程號(hào)。

1.處理一定時(shí)間間隔前的記錄(一秒以上),這樣即使機(jī)器和進(jìn)程號(hào)導(dǎo)致亂序,間隔前也不會(huì)出現(xiàn)亂序情況。

2.單點(diǎn)插入,原來(lái)分布到幾個(gè)點(diǎn)的插入操作,現(xiàn)在統(tǒng)一由一個(gè)點(diǎn)查詢,保證機(jī)器與進(jìn)程號(hào)相同,使用counter算子使記錄有序。

這里,我們用到了第一種辦法。

誤區(qū) 三 、不在DBObject設(shè)置_id使用mongoDB設(shè)置ObjectId?

mongoDB插入操作時(shí),new DBBasicObject()時(shí),大家看到_id是沒(méi)有被填值的,除非手工的設(shè)置_id。那么是否是服務(wù)端設(shè)置的呢?

大家來(lái)看下插入操作的代碼:

實(shí)現(xiàn)類(lèi)

public WriteResult insert(List<DBObject> list, com.mongodb.WriteConcern concern, DBEncoder encoder ){ 
     if (concern == null) { 
       throw new IllegalArgumentException("Write concern can not be null"); 
     } 
     return insert(list, true, concern, encoder); 
   } 

可以看到需要添加,默認(rèn)都為添加

protected WriteResult insert(List<DBObject> list, boolean shouldApply , com.mongodb.WriteConcern concern, DBEncoder encoder ){ 
      if (encoder == null) 
        encoder = DefaultDBEncoder.FACTORY.create(); 
      if ( willTrace() ) { 
        for (DBObject o : list) { 
          trace( "save: " + _fullNameSpace + " " + JSON.serialize( o ) ); 
        } 
      } 
      if ( shouldApply ){ 
        for (DBObject o : list) { 
          apply(o); 
          _checkObject(o, false, false); 
          Object id = o.get("_id"); 
          if (id instanceof ObjectId) { 
            ((ObjectId) id).notNew(); 
          } 
        } 
      } 
      WriteResult last = null; 
      int cur = 0; 
      int maxsize = _mongo.getMaxBsonObjectSize(); 
      while ( cur < list.size() ) { 
        OutMessage om = OutMessage.insert( this , encoder, concern ); 
        for ( ; cur < list.size(); cur++ ){ 
          DBObject o = list.get(cur); 
          om.putObject( o ); 
          // limit for batch insert is 4 x maxbson on server, use 2 x to be safe 
          if ( om.size() > 2 * maxsize ){ 
            cur++; 
            break; 
          } 
        } 
        last = _connector.say( _db , om , concern ); 
      } 
      return last; 
    } 

自動(dòng)添加ObjectId的操作

/** 
  * calls {@link DBCollection#apply(com.mongodb.DBObject, boolean)} with ensureID=true 
  * @param o <code>DBObject</code> to which to add fields 
  * @return the modified parameter object 
  */ 
 public Object apply( DBObject o ){ 
   return apply( o , true ); 
 } 
 /** 
  * calls {@link DBCollection#doapply(com.mongodb.DBObject)}, optionally adding an automatic _id field 
  * @param jo object to add fields to 
  * @param ensureID whether to add an <code>_id</code> field 
  * @return the modified object <code>o</code> 
  */ 
 public Object apply( DBObject jo , boolean ensureID ){ 
   Object id = jo.get( "_id" ); 
   if ( ensureID && id == null ){ 
     id = ObjectId.get(); 
     jo.put( "_id" , id ); 
   } 
   doapply( jo ); 
   return id; 
 } 

可以看到,mongoDB的驅(qū)動(dòng)包中是會(huì)自動(dòng)添加ObjectId的。

save的方法

public WriteResult save( DBObject jo, WriteConcern concern ){ 
    if ( checkReadOnly( true ) ) 
      return null; 
    _checkObject( jo , false , false ); 
    Object id = jo.get( "_id" ); 
    if ( id == null || ( id instanceof ObjectId && ((ObjectId)id).isNew() ) ){ 
      if ( id != null && id instanceof ObjectId ) 
        ((ObjectId)id).notNew(); 
      if ( concern == null ) 
        return insert( jo ); 
      else 
        return insert( jo, concern ); 
    } 
    DBObject q = new BasicDBObject(); 
    q.put( "_id" , id ); 
    if ( concern == null ) 
      return update( q , jo , true , false ); 
    else 
      return update( q , jo , true , false , concern ); 
  } 

綜上所述,默認(rèn)情況下ObjectId是由客戶端生成的,并不是不設(shè)置就由服務(wù)端生成的。

誤區(qū) 四 、findAndModify是否真的可以獲取到自增變量?

DBObject update = new BasicDBObject("$inc", new BasicDBObject("counter", 1)); 
    DBObject query = new BasicDBObject("_id", key); 
    DBObject result = getMongoTemplate().getCollection(collectionName).findAndModify(query, update); 
    if (result == null) 
    { 
      DBObject doc = new BasicDBObject(); 
      doc.put("counter", 1L); 
      doc.put("_id", key); 
      // insert(collectionName, doc); 
      getMongoTemplate().save(doc, collectionName); 
      return 1L; 
    } 
    return (Long) result.get("counter"); 

獲取自增變量會(huì)使用這種方法編寫(xiě),但是,我們執(zhí)行完成后會(huì)發(fā)現(xiàn)。

findAndModify操作,是先執(zhí)行了find,再執(zhí)行了modify,所以當(dāng)result為null時(shí),應(yīng)該新增并返回0

以上所述是小編給大家介紹的MongoDB中ObjectId的誤區(qū)及引起的一系列問(wèn)題,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • 解決java調(diào)用python代碼返回值中文亂碼問(wèn)題

    解決java調(diào)用python代碼返回值中文亂碼問(wèn)題

    這篇文章主要介紹了解決java調(diào)用python代碼返回值中文亂碼問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • JavaCV與FFmpeg音視頻流處理技巧總結(jié)大全

    JavaCV與FFmpeg音視頻流處理技巧總結(jié)大全

    JavaCV是一個(gè)開(kāi)源的Java接口,它為幾個(gè)著名的計(jì)算機(jī)視覺(jué)庫(kù)(如OpenCV、FFmpeg)提供了Java封裝,這篇文章主要給大家介紹了關(guān)于JavaCV與FFmpeg音視頻流處理技巧總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2024-05-05
  • java開(kāi)發(fā)https請(qǐng)求ssl不受信任問(wèn)題解決方法

    java開(kāi)發(fā)https請(qǐng)求ssl不受信任問(wèn)題解決方法

    這篇文章主要介紹了java開(kāi)發(fā)https請(qǐng)求ssl不受信任問(wèn)題解決方法,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • 淺談讓@Value更方便的Spring自定義轉(zhuǎn)換類(lèi)

    淺談讓@Value更方便的Spring自定義轉(zhuǎn)換類(lèi)

    Spring為大家內(nèi)置了不少開(kāi)箱即用的轉(zhuǎn)換類(lèi),如字符串轉(zhuǎn)數(shù)字、字符串轉(zhuǎn)時(shí)間等,但有時(shí)候需要使用自定義的屬性,則需要自定義轉(zhuǎn)換類(lèi)了
    2021-06-06
  • Windows10安裝IDEA 2020.1.2的方法步驟

    Windows10安裝IDEA 2020.1.2的方法步驟

    這篇文章主要介紹了Windows10安裝IDEA 2020.1.2的方法步驟,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Java四種線程池的使用詳解

    Java四種線程池的使用詳解

    本篇文章主要介紹了Java四種線程池的使用詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • 深入剖析Java工廠模式讓你的代碼更靈活

    深入剖析Java工廠模式讓你的代碼更靈活

    Java工廠模式是一種創(chuàng)建對(duì)象的設(shè)計(jì)模式,它可以在不暴露對(duì)象創(chuàng)建邏輯的情況下,將對(duì)象的創(chuàng)建委托給子類(lèi)或者其他對(duì)象。本文就來(lái)深入剖析一下Java工廠模式是如何讓你的代碼更靈活、可擴(kuò)展、易維護(hù)的
    2023-05-05
  • Java使用jmeter進(jìn)行壓力測(cè)試

    Java使用jmeter進(jìn)行壓力測(cè)試

    本篇文章簡(jiǎn)單講一下使用jmeter進(jìn)行壓力測(cè)試。其壓測(cè)思想就是 通過(guò)創(chuàng)建指定數(shù)量的線程,同時(shí)請(qǐng)求指定接口,來(lái)模擬指定數(shù)量用戶同時(shí)進(jìn)行某個(gè)操作的場(chǎng)景,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Spring?Cloud中Sentinel的兩種限流模式介紹

    Spring?Cloud中Sentinel的兩種限流模式介紹

    如何使用Sentinel做流量控制呢?這篇文章就來(lái)為大家詳細(xì)介紹了Spring?Cloud中Sentinel的兩種限流模式,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-05-05
  • Spring Boot的properties配置文件讀取

    Spring Boot的properties配置文件讀取

    這篇文章主要介紹了Spring Boot的properties配置文件讀取,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06

最新評(píng)論