我有一个User
类,它嵌入一个JsonObject
来表示用户的字段。这个类看起来像这样:
class User {
private JsonObject data;
public User(...) {
data = new JsonObject();
data.put("...", ...).put(..., ...);
}
public String getID() { return data.getString("_id"); }
// more getters, setters
// DB access methods
public static userSave(MongoClient mc, User user){
// some house keeping
mc.save("users", user.jsonObject(), ar -> {
if(ar.succeeded()) { ... } else { ... }
});
}
}
我花了超过半天的时间来弄清楚为什么有时user.getID()
的调用会产生以下错误:ClassCastException: class io.vertx.core.json.JsonObject cannot be cast to class java.lang.CharSequence
。我缩小到userSave()
方法的范围,更具体地说,缩小到MongoClient::save()
,它实际上产生了一种副作用,该副作用将data._id
从类似
"_id" : "5ceb8ebb9790855fad9be2fc"
变成类似
"_id" : {
"$oid" : "5ceb8ebb9790855fad9be2fc"
}
这由vertx文档确认,该文档指出“ 此操作可能会更改文档参数的_id字段”。实际上,对于其他写入方法(例如插入)也是如此。
我提供了两种解决方案,并且在保持save()
字段为最新状态的同时正确完成_id
的问题很少。
S1 一种实现方法是保存Json对象的副本,而不是对象本身,即mc.save("users", user.jsonObject().copy(), ar -> {...});
。从长远来看,这可能会很昂贵。
S2 另一种方法是“记住” _id
,然后将其重新插入data
部分的if(ar.succeeded()) {data.put("_id", oidValue); ...}
对象中。但是由于我们是异步的,所以我认为save()
和data.put(...)
之间的间隔不是原子的吗?
Q1 :解决方案 S1 假定ID不变,即字符串5ceb8ebb9790855fad9be2fc
不变。我们对此有保证吗?
第二季度:正确实施saveUser()
的正确方法是什么?
编辑:用于创建MongoClient
的配置JSON对象用户如下(以防万一):
"main_pool" : {
"pool_name" : "mongodb",
"host" : "localhost",
"port" : 27017,
"db_name" : "appdb",
"username" : "xxxxxxxxx",
"password" : "xxxxxxxxx",
"authSource" : "admin",
"maxPoolSize" : 5,
"minPoolSize" : 1,
"useObjectId" : true,
"connectTimeoutMS" : 5000,
"socketTimeoutMS" : 5000,
"serverSelectionTimeoutMS" : 5000
}