【问题标题】:Error Handling with Spring Data and Mongo Java DriverSpring Data 和 Mongo Java 驱动程序的错误处理
【发布时间】:2020-02-21 23:43:40
【问题描述】:

在与 MongoDB 交互时,我无法理解如何正确接收和处理 DB 约束错误。

我正在使用:

  • MongoDB java 驱动程序 - 2.11
  • spring-data-mongodb - 1.2.1.RELEASE
  • spring-framework-core - 3.1.0.RELEASE

我正在使用 mongoTemplate.insert 并给它一个代表足球队的“persistentTeam”对象。我根据一些业务规则自定义生成文档的 _id 字段。生成此 _id 的算法可能会匹配现有对象,在这种情况下,我想进行一些错误处理。

使用默认配置,如果我插入一个具有重复 ID 的对象,我不会从数据库返回任何错误。这与 mongo 文档相矛盾,该文档说默认 mongo 驱动程序配置是“ACKNOWLEDGED”,在这种情况下应该引发异常:http://docs.mongodb.org/manual/release-notes/drivers-write-concern/ 我查看了 2.11 mongo 驱动程序代码,果然,在 Mongo.java 中,默认写入问题是 WriteConcern。正常(相当于未确认)。好吧,我会解决的。

编辑:关于代码/文档差异的一些附加说明:Mongo Java 驱动程序 2.10.0 引入了 MongoClient.java,它取代了 Mongo.java。但是,spring-framework-core 3.1.0.RELEASE 没有与这个新类集成。这就是为什么我没有得到预期的默认值。

我更新了我的 mongo 工厂:

<bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean">
    <property name="host" value="${db.url}" />
    <property name="writeConcern" value="ACKNOWLEDGED" />
</bean>

现在,当我尝试插入具有重复主键的对象时,我看到以下错误:

{"com.mongodb.MongoException$DuplicateKey: {
\"serverUsed\" : \"localhost/127.0.0.1:27017\" ,
\"err\" : \"E11000 duplicate key error index: Sports.persistentTeam.$_id_  dup key: { : 5019964551640473690 }\" ,
\"code\" : 11000 ,
\"n\" : 0 ,
\"connectionId\" : 21 , \"ok\" : 1.0}\n
\tat com.mongodb.CommandResult.getException(CommandResult.java:74)\n
\tat com.mongodb.CommandResult.throwOnError(CommandResult.java:110)\n
\tat com.mongodb.DBTCPConnector._checkWriteError(DBTCPConnector.java:102)\n
\tat com.mongodb.DBTCPConnector.say(DBTCPConnector.java:142)\n
\tat com.mongodb.DBTCPConnector.say(DBTCPConnector.java:115)\n
\tat com.mongodb.DBApiLayer$MyCollection.insert(DBApiLayer.java:248)\n
\tat com.mongodb.DBApiLayer$MyCollection.insert(DBApiLayer.java:204)\n
\tat com.mongodb.DBCollection.insert(DBCollection.java:76)\n
\tat com.mongodb.DBCollection.insert(DBCollection.java:60)\n
\tat com.mongodb.DBCollection.insert(DBCollection.java:105)\n
\tat org.springframework.data.mongodb.core.MongoTemplate$8.doInCollection(MongoTemplate.java:835)\n
\tat org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:388)\n
\tat org.springframework.data.mongodb.core.MongoTemplate.insertDBObject(MongoTemplate.java:830)\n
\tat org.springframework.data.mongodb.core.MongoTemplate.doInsert(MongoTemplate.java:659)\n
\tat org.springframework.data.mongodb.core.MongoTemplate.insert(MongoTemplate.java:613)\n
\tat org.springframework.data.mongodb.core.MongoTemplate.insert(MongoTemplate.java:604)\n
\tat com.example.persistence.dao.MongoDataServiceDao.create(MongoDataServiceDao.java:96)\n
\tat com.example.persistence.PersistenceImpl.createObject(PersistenceImpl.java:944)\n
}

好的,太好了!一切正常。不是真的。当我尝试插入应该成功的东西时,我得到了这个错误:

{
com.mongodb.WriteConcernException: 
{ \"serverUsed\" : \"localhost/127.0.0.1:27017\" ,
\"n\" : 0 ,
\"connectionId\" : 20 ,
\"wnote\" : \"no replication has been enabled, so w=\\\"ACKNOWLEDGED\\\" won't work\" ,
\"err\" : \"norepl\" ,
\"ok\" : 1.0}
\n\tat com.mongodb.CommandResult.getException(CommandResult.java:77)\n
\tat com.mongodb.CommandResult.throwOnError(CommandResult.java:110)\n
\tat com.mongodb.DBTCPConnector._checkWriteError(DBTCPConnector.java:102)\n
\tat com.mongodb.DBTCPConnector.say(DBTCPConnector.java:142)\n
\tat com.mongodb.DBTCPConnector.say(DBTCPConnector.java:115)\n
\tat com.mongodb.DBApiLayer$MyCollection.insert(DBApiLayer.java:248)\n
\tat com.mongodb.DBApiLayer$MyCollection.insert(DBApiLayer.java:204)\n
\tat com.mongodb.DBCollection.insert(DBCollection.java:76)\n
\tat com.mongodb.DBCollection.insert(DBCollection.java:60)\n
\tat com.mongodb.DBCollection.insert(DBCollection.java:105)\n
\tat org.springframework.data.mongodb.core.MongoTemplate$8.doInCollection(MongoTemplate.java:835)\n
\tat org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:388)\n
\tat org.springframework.data.mongodb.core.MongoTemplate.insertDBObject(MongoTemplate.java:830)\n
\tat org.springframework.data.mongodb.core.MongoTemplate.doInsert(MongoTemplate.java:659)\n
\tat org.springframework.data.mongodb.core.MongoTemplate.insert(MongoTemplate.java:613)\n
\tat org.springframework.data.mongodb.core.MongoTemplate.insert(MongoTemplate.java:604)\n
\tat com.example.mongo.persistence.dao.MongoDataServiceDao.create(MongoDataServiceDao.java:96)\n
\tat com.example.persistence.PersistenceImpl.createObject(PersistenceImpl.java:944)\n
}

所以这有点令人困惑。该错误告诉我我不能在没有复制的情况下使用 ACKNOWLEDGED。但是文档并没有这样说。还有其他 WriteConcern 模式明确声明它们检查对副本的写入...... ACKNOWLEDGED 应该只验证对主要的写入。毕竟,写入实际上成功了。我在这里做什么?只是埋葬第二个例外并忘记它吗?

【问题讨论】:

    标签: java mongodb spring-data-mongodb


    【解决方案1】:

    这是因为您使用的是 WriteConcern 的字符串变体。

    这样,您的驱动程序将其视为副本标签集 Write Concern。因此例外。

    使用 WriteConcern 构造函数的 int 变体,并将其值 1(如 {w=1})作为确认值。

    【讨论】:

    • 您的回答解决了我的问题,所以我接受了。但这很奇怪,因为 WriteConcern 代码表明 ACKNOWLEDGED=1。但是,您的声明 “无论如何,因为它是默认的 Write Concern,您可以完全跳过它” 是不正确的,尽管它与当前的 Mongo Docs 一致。如果不手动将 writeConcern 配置为 1 或更大,我绝对不会在我的测试用例中遇到重复的关键错误。
    • 另外,在 com.mongodb.Mongo 版本 2.11.0 的第 636 行,您可以清楚地看到默认的 writeConcen 是 WriteConcern.NORMAL(整数值 0)。
    • 你是对的,当前 Java 驱动规范的默认值是UNACKNOWLEDGED(又名NORMAL)谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-25
    相关资源
    最近更新 更多