spring boot mongodb 复制集、主从实现

1.上篇文章简单的介绍了Mongodb,和做了一个简单的SpringBoot - Mongodb单机实现,本文将介绍 SpringBoot mongodb replica set复制集读写分离的实现,主库:Primary , 从库:Secondary
复制主要用于备份、灾难恢复和读写分离,可以应对更多的读操作,当主库挂了可以从副本集中选一个主节点,更多作用请自行百度,怎么搭建复制集请参考我之前的 Mongodb安装与设置副本集 二 教程

2.spring boot 项目 Pom.xml中添加 spring-boot-starter-data-mongodb 包引用

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

3.在application.properties中配置连接信息(使用yaml配置比较优雅,但我配置后未能实现连接)

spring.data.mongodb.primary.host=192.168.68.128
spring.data.mongodb.primary.port=27017
spring.data.mongodb.primary.database=test
spring.data.mongodb.primary.username=admin
spring.data.mongodb.primary.password=admin

spring.data.mongodb.secondary.host=192.168.68.129
spring.data.mongodb.secondary.port=27017
spring.data.mongodb.secondary.database=test
spring.data.mongodb.secondary.username=admin
spring.data.mongodb.secondary.password=admin

4.创建一个实体 User ,重写toString()方法,并在类上注解 @Document(collection = “user”) ,表名

@Document(collection = "user")
public class User {

    private Long mid;
    private String userName;
    private String passWord;

    @Override
    public String toString() {
        return "User{" +
                "mid=" + mid +
                ", userName='" + userName + '\'' +
                ", passWord='" + passWord + '\'' +
                '}';
    }
    //Getter Setter....
}

5.重点–创建一个抽象类 AbstractMongoConfig.class , 创建一个主库配置类 PrimaryMongoConfig.class 和一个从库配置类 SecondaryMongoConfig.class 继承抽象类,重写 getMongoTemplate() 方法,用户返回 MongoTemplate 对象

public abstract class AbstractMongoConfig {

    // Mongo DB Properties
    private String host, database, username, password;
    private int port;

    /*
     * Method that creates MongoDbFactory Common to both of the MongoDb
     * connections
     */
    public MongoDbFactory mongoDbFactory() throws Exception {
        String url = "mongodb://"+username+":"+password+"@"+host+":"+port+"/"+database;
        MongoClientURI uri = new MongoClientURI(url);
        return new SimpleMongoDbFactory(new MongoClient(uri),database);
    }

    /*
     * Factory method to create the MongoTemplate
     */
    abstract public MongoTemplate getMongoTemplate() throws Exception;

    //host, database, username, password Getter Setter....
}
@Configuration
//在application.properties中查找 spring.data.mongodb.primary 开头的配置信息
@ConfigurationProperties(prefix = "spring.data.mongodb.primary") 
public class PrimaryMongoConfig extends AbstractMongoConfig {

    /**
     * Implementation of the MongoTemplate factory method
     * @Bean gives a name (primaryMongoTemplate) to the created MongoTemplate instance
     * @Primary declares that if MongoTemplate is autowired without providing a specific name,
     * this is the instance which will be mapped by         default
     */
    @Primary
    @Override
    public @Bean(name = "primaryMongoTemplate") MongoTemplate getMongoTemplate() throws Exception {
        return new MongoTemplate(mongoDbFactory());
    }
}
@Configuration  
//在application.properties中查找 spring.data.mongodb.secondary开头的配置信息
@ConfigurationProperties(prefix = "spring.data.mongodb.secondary")  
public class SecondaryMongoConfig extends  AbstractMongoConfig {

    /**
     * Implementation of the MongoTemplate factory method
     * @Bean gives a name (primaryMongoTemplate) to the created MongoTemplate instance
     * Note that this method doesn't have @Primary
     */
    @Override
    public @Bean(name = "secondaryMongoTemplate") MongoTemplate getMongoTemplate() throws Exception {
        return new MongoTemplate(mongoDbFactory());
    }
}

6.UserDaoImpl类(省略了UserDao接口类),使用配置类,获取 MongoTemplate

@Repository
public class UserDaoImpl implements UserDao{

    // Using MongoTemplate for primary database
    @Autowired
    @Qualifier(value = "primaryMongoTemplate") //和上面配置类中的Bean(name)的名字对应
    protected MongoTemplate primaryMongoTemplate;

    // Using mongoTemplate for secondary database
    @Autowired
    @Qualifier(value = "secondaryMongoTemplate")//和上面配置类中的Bean(name)的名字对应
    protected MongoTemplate secondaryMongoTemplate;

    //主库存
    @Override
    public void savePrimary(User user) {
        primaryMongoTemplate.save(user);
    }
    //从库存
    @Override
    public void saveSecondary(User user) {
        secondaryMongoTemplate.save(user);
    }
    //从库读
    @Override
    public User findUserByUserName(String userName) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userName").is(userName));
        return secondaryMongoTemplate.findOne(query,User.class);
    }

}

7.测试,在测试类中运行如下代码:

//1.测试主库存
@Test
public void testSavePrimary() throws Exception {
    User pUser = new User();
    pUser.setMid(11L);
    pUser.setUserName("primary");
    pUser.setPassWord("123456");
    userDao.savePrimary(pUser);
}
//2.测试从库存
@Test
public void testSaveSecondary() throws Exception {
    User pSecond = new User();
    pSecond.setMid(12L);
    pSecond.setUserName("secondary");
    pSecond.setPassWord("123456");
    userDao.savePrimary(pSecond);
}
//3.从库读
@Test
public void testFindUser() throws Exception {
    User pSecond = userDao.findUserByUserName("secondary");
    System.out.println(pSecond.toString());
}

8.测试结果正确的保存和读取出来了,主库-从库保存的数据,从库读取的数据直接用toString()方法打印到控制台了:
这里写图片描述
这里写图片描述

实现读写分离还有另外一个方式:使用 lombok和spring-boot-autoconfigure 包,但我未实现出来,供大家参考和百度。

最后总结,此方式还不是太优雅,只能算是一个简单实现,遗留问题:要是有多个从库该怎么办,在配置文件中配置多个数据源?然后写多个从库配置类?调用的时候再写一个轮询方法,用来获取MongoTemplate?这些都是应该考虑的问题,现在的方式还不够优雅。。。有待研究与改进。希望那位大大指教指教

猜你喜欢

转载自blog.csdn.net/zhuyu19911016520/article/details/79997650