Using MongoDB Replica Set With Spring MongoDB 1.0.0.RC1

The primary means for replication is to ensure data survives single or multiple machine failures. The more replicas you have, the more likely is your data to survive one or more hardware crashes. With three replicas, you can afford to lose two nodes and still serve the data. MongoDB supports two forms of replication, Replica Sets and Master Slave. Replica Sets is the recommended way to do replication in MongoDB and will cover only Replica Sets in this post.

Couple of weeks back I was working in POC where we need to set up MongoDB replication. As I am Spring aficionado I decided to use Spring MongoDB to interact with Replica Set. We used Spring Roo to quickly bootstrap the project. All the project setup, Spring MongoDB setup, JUnit test cases, evern Spring MVC UI was created in minutes thanks to Spring Roo. I am big Spring Roo fan — I just love it. Thanks SpringSource for such an amazing project. Spring Roo uses Spring MongoDB version 1.0.0.M5 which has a bug that it does not support WriteConcern value REPLICAS_SAFE. But with the current release 1.0.0.RC1 that issue has been fixed and now you can use REPLICAS_SAFE. REPLICAS_SAFE is the recommended value for WriteConcern in case of replication.  This is a step by step guide from creation of Spring project to working MongoDB replica set.

  1. Create the project using Spring Roo. If you are not aware of Spring Roo you can read my Spring Roo series. I am using Spring Roo to quickly configure a Spring MongoDB project.
    project --topLevelPackage com.xebia.mongodb.replication --projectName mongodb-replication-demo --java 6
    mongo setup --databaseName bookshop --host localhost --port 27017
    entity mongo --class ~.domain.Book --testAutomatically --identifierType org.bson.types.ObjectId
    field string --fieldName title --notNull
    field string --fieldName author --notNull
    field number --type double --fieldName price --notNull
    repository mongo --interface ~.repository.BookRepository --entity ~.domain.Book

    This will create a Spring maven project, configure MongoDB to work with Spring, create one Collection Book and will add three fields title, author, and price to the collection. All the CRUD operations will carried out using BookRepository.

  2.  Start the MongoDB server using ./mongod and run BookIntegrationTest and make sure all tests pass.
  3. Setup replica set following the MongoDB documentation
  4. Update the applicationContext-mongo.xml as shown below but before add the property mongo.replicaset which will have all nodes.
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <beans xmlns="" xmlns:cloud="" xmlns:context="" xmlns:mongo="" xmlns:xsi="" xsi:schemaLocation="">
        <mongo:db-factory dbname="${mongo.database}" id="mongoDbFactory" mongo-ref="mongo"/>
        <mongo:repositories base-package="com.xebia.mongodb.replication"/>
        <!-- To translate any MongoExceptions thrown in @Repository annotated classes -->
        <bean class="" id="mongoTemplate">
            <constructor-arg ref="mongoDbFactory"/>
    	<mongo:mongo id="mongo" replica-set="${mongo.replicaset}" write-concern="REPLICA_SAFE">
    		<mongo:options auto-connect-retry="true"/>

    If you run the tests again all the tests will fail and you will see following exception.

    Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from file [/home/shekhar/dev/workspaces/writing/mongodb-replication-demo/target/classes/META-INF/spring/applicationContext-mongo.xml]; nested exception is java.lang.ArrayIndexOutOfBoundsException: 1
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.

    The reason for this exception is because there is a bug in Spring MongoDB 1.0.0.M5 which is not able to parse WriteConcern REPLICA_SAFE value.

  5. To make it work we have to work with Spring MongoDB latest version 1.0.0.RC1. This is released just 3 days back on 7th December 2011.Update the pom.xml with 1.0.0.RC1.

    Run the BookIntegrationTest the tests will fail again and see the following exception stacktraces.

    java.lang.NoSuchMethodError: org.springframework.core.annotation.AnnotationUtils
    at org.springframework.transaction.annotation.SpringTransactionAnnotationParser
  6. To make it ran you have to use latest Spring version 3.1.0.RC2 in pom.xml
  7. Final change you need to make is in applicationContext-mongo.xml. Change the value of write-concern to REPLICAS_SAFE.
    <mongo:mongo id="mongo" replica-set="${mongo.replicaset}" write-concern="REPLICAS_SAFE">
    	<mongo:options auto-connect-retry="true"/>
  8. Run the tests and all the tests will pass.