1. 程式人生 > >升級mongo3.2.1後遇到的資料重複的問題

升級mongo3.2.1後遇到的資料重複的問題

因為5分鐘的uv資料1分鐘更新一次mongo,

所以使用了mongo的update方法(db.collection.update(query,update,true,false)),

設定第三個引數upsert為true,以實現資料不存在的時候直接寫入,存在的時候更新的場景。

最近,在由mongo3.0.7升級到mongo3.2.1之後,發現,同樣查詢條件的資料,存在重複的情況。比如id=x是查詢條件,根據update方法,找這條資料,往後面新增別的欄位,如果那個欄位已經存在,就往上面累加值,如果那個欄位不存在,就加進去,如果找不到id=x的資料就直接插入,也就是id=x這個條件的資料,始終只有一條。可實際卻出現了多條資料。

通過java程式碼起兩個執行緒呼叫update的api,在表中不存在符合查詢條件的資料的前提下,針對mongo3.2.1操作的時候,偶爾會發生符合更新條件的資料,寫入兩條的情況;針對mongo3.0.7在相同的測試次數下,未發生寫入兩條的情況。

public  void run(){
    try {
        MongoURI uri = new MongoURI("mongodb://IP地址:埠號/test");
        Mongo mongo = newMongo(uri);
        DB db = mongo.getDB(uri.getDatabase());
        DBCollection collection = db.getCollection("test1"

);

        BasicDBObject query = new BasicDBObject();
        query.put("ts", Long.valueOf("1455426000000"));
        query.put("lid", "102016021");
        query.put("type", "uv");

        String p1="pc";
        DBObject mappedUpdateObject =BasicDBObjectBuilder.start().push("$inc").add(p1,2).get();


        collection.update(query,mappedUpdateObject, true
,false);

        mongo.close();
    } catch (Exception e) {
        // Die fast
       
throw new RuntimeException(e);
    }
}

publicstatic void main(String[]args){
    Test7 m=new Test7();//本類的名字
    Test5 n=new Test5();//功能相同的另外一個類,只不過,要寫入的資料有差別,pc改成mobile,或者2改成3這樣
    Thread t1 = new Thread(m);
    Thread t2= new Thread(n);
    t1.start();
    t2.start();

}

執行結果,在3.0.7的mongo上,不管起幾個執行緒,結果始終只有一條。

而在3.2.1上,有時候是多條,有時候是一條。

根據網上搜索的資料,找到一個遇到類似情況的人,有人丟擲一段mongo文件,

If all update() operations complete the query portionbefore any client successfully inserts data,and there is no uniqueindex on the name field, then each update operation may perform an insert.

指明瞭可能會發生此類問題,規避的措施是,在查詢條件上建立唯一索引,

試著建了另外一張表,在lid,ts,type上建了唯一索引,

發現數據是不會重複多條了,但是是在偶發多條的時候,只有一條成功寫入,另外一條不是更新上去,而是扔掉了。

以下為在網路上找到的資料:

在用C++MongoDB執行update操作的時候,如果設定了upsert引數為true,則會自動插入不存在的資料。在高併發環境下,會導致資料重複。

解決方法是為查詢條件新增unique index,參考官方文件:

http://docs.mongodb.org/manual/core/write-operations-atomicity/

http://docs.mongodb.org/manual/core/index-unique/#index-type-unique

經過高壓測試後,證明這個解決方案是靠譜的。


作者:達一夫
連結:http://www.zhihu.com/question/21703021/answer/20694219
來源:知乎

木有人回答,我自己來答吧。
首先mongodb的文件有解釋:
If all update() operations complete the query portion before any clientsuccessfully inserts data,and there is no unique index on the namefield, then each update operation may perform an insert.

但這個解釋不完全,在當前文件已經存在的情況下,多併發upsert,也可能插入多條,並且我們驗證了這個可能性的存在。

嗯。。。我再新增一個問題吧。
find到的資料可能不是最新的,下一次find才是,這造成我們一些詭異的問題。