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