Обработка ошибок с помощью Spring Data и Java-драйвера Mongo

У меня возникли проблемы с пониманием того, как правильно получать и обрабатывать ошибки ограничений БД при взаимодействии с MongoDB.

Я использую:

  • Java-драйвер MongoDB — 2.11
  • весна-данные-mongodb - 1.2.1.RELEASE
  • spring-framework-core - 3.1.0.RELEASE

Я использую mongoTemplate.insert и даю ему объект «persistentTeam», который представляет футбольную команду. Я специально генерирую поле _id документа в соответствии с некоторыми бизнес-правилами. Вполне возможно, что алгоритм генерации этого _id будет соответствовать существующему объекту, и в этом случае я хочу заняться обработкой ошибок.

С конфигурацией по умолчанию, если я вставлю объект с повторяющимся идентификатором, я не получу сообщение об ошибке из БД. Это противоречит документации монго, в которой говорится, что конфигурация драйвера монго по умолчанию «ПОДТВЕРЖДЕНА», что в этом случае должно вызывать исключение: http://docs.mongodb.org/manual/release-notes/drivers-write-беспокойство/ Я просмотрел код драйвера mongo 2.11 и, конечно же, в Mongo. java по умолчанию проблема записи — WriteConcern.NORMAL (эквивалент UNACKNOWLEDGED). Хорошо, я поработаю.

РЕДАКТИРОВАТЬ: Некоторые дополнительные примечания о несоответствии кода/документации: Mongo Java Driver 2.10.0 представил MongoClient.java, который заменяет Mongo.java. Однако spring-framework-core 3.1.0.RELEASE не интегрируется с этим новым классом. Вот почему я не получаю ожидаемого значения по умолчанию.

Я обновил свою фабрику монго:

<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 должен проверять только запись на первичный. И после всего этого запись действительно удалась. Что мне здесь делать? Просто похоронить это второе исключение и забыть о нем?


person skelly    schedule 25.07.2013    source источник


Ответы (1)


Это связано с тем, что вы используете строковый вариант WriteConcern.

Таким образом, ваш драйвер считает, что это набор тегов реплики Write Concern. Отсюда исключение.

Используйте вариант int для конструктора WriteConcern и присвойте ему значение 1 (как в {w=1}), которое является значением для подтверждения.

person Ori Dar    schedule 29.07.2013
comment
Ваш ответ решил мою проблему, поэтому я принимаю его. Это странно, поскольку код WriteConcern предполагает, что ACKNOWLEDGED=1. Однако ваше утверждение о том, что В любом случае, поскольку это проблема записи по умолчанию, вы можете вообще ее пропустить, неверно, несмотря на то, что оно согласуется с текущими документами Mongo Docs. Я абсолютно не получаю дублирующихся ключевых ошибок в своем тестовом примере без ручной настройки writeConcern на 1 или выше. - person skelly; 30.07.2013
comment
Кроме того, в строке 636 файла com.mongodb.Mongo версии 2.11.0 вы можете ясно увидеть, что значением writeConcen по умолчанию является WriteConcern.NORMAL (целочисленное значение 0). - person skelly; 30.07.2013
comment
Вы правы, по умолчанию для текущей спецификации драйвера Java используется UNACKNOWLEDGED (он же NORMAL). Спасибо. - person Ori Dar; 30.07.2013