为什么mongodb似乎保存了一些二进制对象而不是其他对象?

Ale*_*x W 7 java cometd mongodb

我不知道从哪里开始或哪些信息相关,请告诉我哪些其他信息可能有助于解决此问题.

我正在开发一个简单的cometd应用程序,我正在使用mongodb作为我的存储后端.我在应用程序启动时获取了一个mongodb实例,并将此实例用于所有查询.事实上,这是由mongo java驱动程序文档推荐的,如下所述:http://www.mongodb.org/display/DOCS/Java+Driver+Concurrency.我正在抓住吸管认为这个问题与线程安全有关,但根据该链接,mongodb完全是线程安全的.

这是有趣的地方.我有一个课程延伸BasicDBObject.

public class MyBasicDBObject {

    private static final String MAP = "map";

    public boolean updateMapAnd(String submap, String key, byte[] value) {
         Map topMap = (Map)this.get(MAP);
         Map embeddedMap = topMap.get(submap);
         byte[] oldValue = embeddedMap.get(key);

         newValue = UtilityClass.binaryAnd(oldValue, value);

         embeddedMap.put(key, newValue);
         topMap.put(submap, embeddedMap);
         this.put(MAP, topMap);
    }

    public boolean updateMapXor(String submap, String key, byte[] value) {
         Map topMap = (Map)this.get(MAP);
         Map embeddedMap = topMap.get(submap);
         byte[] oldValue = embeddedMap.get(key);

         newValue = UtilityClass.binaryXor(oldValue, value);

         embeddedMap.put(key, newValue);
         topMap.put(submap, embeddedMap);
         this.put(MAP, topMap);
    }
}
Run Code Online (Sandbox Code Playgroud)

接下来的两个扩展的骨架类MyBasicDBObject.

public class FirstDBObject extends MyBasicDBObject { //no code }

public class SecondDBObject extends MyBasicDBObject { //no code }
Run Code Online (Sandbox Code Playgroud)

我以这种方式设置类的唯一原因是为了提高在同一范围内处理这两个对象的代码可读性.这让我做以下事情......

//a cometd service callback
public void updateMapObjectsFoo(ServerSession remote, Message message) {

    //locate the objects to update...
    FirstDBObject first = (FirstDBObject) firstCollection.findOne({ ... });
    SecondDBObject second = (SecondDBObject) secondCollection.findOne({ ... });

    //update them as follows
    first.updateMapAnd("default", "someKey1", newBinaryData1);
    second.updateMapAnd("default", "someKey2", newBinaryData2);

    //save (update) them to their respective collections
    firstCollection.save(first);
    secondCollection.save(second);
}

public void updateMapObjectsBar(ServerSession remote, Message message) {

    //locate the objects to update...
    FirstDBObject first = (FirstDBObject) firstCollection.findOne({ ... });
    SecondDBObject second = (SecondDBObject) secondCollection.findOne({ ... });

    /** 
     * the only difference is these two calls 
     */
    first.updateMapXor("default", "someKey1", newBinaryData1);
    second.updateMapXor("default", "someKey2", newBinaryData2);

    //save (update) them to their respective collections
    firstCollection.save(first);
    secondCollection.save(second);
}
Run Code Online (Sandbox Code Playgroud)

UtilityClass不完全一样的方法被命名为,位&和位^通过循环通过字节数组.

这是我完全迷失的地方. updateMapObjectsFoo()工程完全按照预期,双方firstsecond反映在数据库中的变化. updateMapObjectsBar()另一方面,只能设法正确更新first.

通过调试检查updateMapObjectsBar()显示二进制对象实际上已在两个对象上正确更新,但是当我转到mongo shell来调查问题时,我看到它first在DB中更新而second不是.我在哪里得到线程安全与它有关的想法?让我secondCollection烦恼的唯一区别是其他cometd服务使用的firstCollection不是.这似乎与一方面相关,但在另一方面却没有,因为Foo有效并且Bar没有.

我已将代码分开并将其重新组合在一起并继续回到同样的问题.世界上到底发生了什么?

似乎我遗漏了所有这些最相关的部分,这是java泛型的噩梦和mongodb驱动程序依赖于该语言的这一特性. BasicDBObject本质上是一个包装器Map<String, Object>.问题是,一旦将对象存储在该映射中,就必须将其强制转换为放入该映射时的对象.是的,这似乎是非常明显的,我在发布这个问题之前就已经知道了.

我无法确定究竟发生了什么,但我会向java + mongodb用户提供这个建议.您将投射,很多,数据结构越复杂,您需要的投射就越多.长话短说,不要这样做:

DBObject obj = (DBObject) collection.findOne(new BasicDBObject("_id", new ObjectId((String)anotherObj.get("objId"))));
Run Code Online (Sandbox Code Playgroud)

当你做快速原型时,一个衬垫很诱人,但是当你一遍又一遍地开始这样做时,你一定会犯错误.现在编写更多代码,以后减少挫折感:

DBObject query = new DBObject();
String objId = (String) anotherObj.get("objId");
query.put("_id", new ObjectId(objId));
obj = (DBObject) collection.findOne(query);
Run Code Online (Sandbox Code Playgroud)

我认为这是令人讨厌的冗长,但我应该期待与Mongo直接交互,而不是使用某种类型的库来让我的生活更轻松.我在这个问题上愚弄了自己,但希望有人能从我的错误中吸取教训,并为自己省去很多挫折感.

感谢大家的帮助.

Fuw*_*jax 2

这很可能是多线程问题。虽然您正确地认为,如果只有一个 Mongo 实例,Mongo、DB 和 DBCollection 对象是线程安全的,但 DBObject 不是线程安全的。但即使它们是线程安全的,您的 updateMapObjectsFoo/Bar 方法也不会执行任何操作来确保它们是数据库上的原子操作。

不幸的是,您需要对代码进行的更改比仅仅散布一些“同步”关键字更强烈。看看http://www.mongodb.org/display/DOCS/Atomic+Operations是否不能帮助您了解问题的范围和一些潜在的解决方案。