首页 文章

可以将Spring Data MongoDB配置为支持每个存储库的不同数据库吗?

提问于
浏览
2

过去一周我一直在努力将Spring Data MongoDB成功集成到我们的应用程序中 . 我们使用相当普遍的做法,为我们依赖的每个集合提供单独的数据库 . 例如,TenantConfiguration数据库仅包含TenantConfigurations集合 .

我已经多次阅读了文档,并通过代码搜索了解决方案但没有发现任何内容 . 当然这样一个广泛采用的项目对这个问题有一些解决方案吗?我目前的尝试看起来像这样:

@Configuration
@EnableMongoRepositories(basePackages = "com.whatever.service.repository",
        basePackageClasses = TenantConfigurationRepository.class,
        mongoTemplateRef = "tenantConfigurationTemplate")
public class TenantConfigurationRepositoryConfig {

    @Value("${mongo.hosts}")
    private List<String> mongoHosts;

    @Bean
    public MongoTemplate tenantConfigurationTemplate() throws Exception {
        final List<ServerAddress> serverAddresses = new ArrayList<>();
        for (String host : mongoHosts) {
            serverAddresses.add(new ServerAddress(host, 27017));
        }

        final MongoClientOptions clientOptions = new MongoClientOptions.Builder()
                .connectTimeout(25000)
                .readPreference(ReadPreference.primaryPreferred())
                .build();

        final MongoClient client = new MongoClient(serverAddresses, clientOptions);
        return new MongoTemplate(client, "TenantConfiguration");
    }
}

以下是其他单个存储库配置之一:

@Configuration
@EnableMongoRepositories(basePackages = "com.whatever.service.repository",
        basePackageClasses = RegisteredCardRepository.class,
        mongoTemplateRef = "registeredCardTemplate")
public class RegisteredCardRepositoryConfig {

    @Value("${mongo.hosts}")
    private List<String> mongoHosts;

    @Bean
    public MongoTemplate registeredCardTemplate() throws Exception {
        final List<ServerAddress> serverAddresses = new ArrayList<>();
        for (String host : mongoHosts) {
            serverAddresses.add(new ServerAddress(host, 27017));
        }

        final MongoClientOptions clientOptions = new MongoClientOptions.Builder()
                .connectTimeout(25000)
                .readPreference(ReadPreference.primaryPreferred())
                .build();

        final MongoClient client = new MongoClient(serverAddresses, clientOptions);
        return new MongoTemplate(client, "RegisteredCard");
    }
}

现在这里是RegisteredCard存储库的实际存储库定义:

@Repository
public interface RegisteredCardRepository extends MongoRepository<RegisteredCard, Guid>,
        QueryDslPredicateExecutor<RegisteredCard> { }

这对我来说都很有意义,各个配置通过注释的 mongoTemplateRef 参数唯一地标识它们配置的特定存储库接口以及与该存储库一起使用的特定模板bean . 至少,这就是文档似乎意味着它应该起作用的方式 .

实际上,当我启动应用程序时,RegisteredCard存储库解析为MongoDB存储库实例,其中包含绑定到TenantConfiguration数据库的关联 MongoDbFactory . 实际上,每个存储库都会收到相同的,不正确的MongoOperations对象 . 尽管每个存储库都有自己独特的配置,但似乎首先访问的数据库仍然是每个存储库的目标数据库 .

这个问题有什么解决方案吗?

1 回答

  • 3

    这花了我差不多一个星期,但实际上我找到了一个可以解决这个问题的方法 . 这是我在研究这个问题时所掌握的事实的快速消解:

    • @EnableMongoRepositories(basePackageClasses = Whatever.class) 只是使用限定类名来指示它应扫描所有已定义数据模型的包 . 这完全等同于 @EnableMongoRepositories(basePackageClasses = "com.mypackage.whatevers") 如果 Whatever.class 驻留在该包中 .

    • @EnableMongoRepositories 不可重复,但可用于注释多个类 . 其他SO对话已经涵盖了这一点,但在此重复 . 您需要定义多个存储库配置类; one for each database you intend to interact with .

    • 每个存储库配置必须在 @EnableMongoRepositories 注释中指定自己的 MongoTemplate 实例 . 你可以只提供一个 Mongo bean,但 MongoTemplate 依赖于特定的 MongoMappingContext .

    • @EnableMongoRepositories 注释有助于定义映射上下文,这可以理解数据模型的结构以及如何序列化它们 . 它还能理解 @Document@Field 注释,并且可以解决持久存在的问题 . Mongo模板实例是您指定要与之交互的数据库的位置 . 因此,通过提供带有 basePackage 属性和 mongoTemplateRef 属性的 @EnableMongoRepositories 注释,您可以将Spring Data Mongo告诉"take these models and persist them in this specific database" .

    对此解决方案的不幸要求是您必须根据数据库所属的数据库将数据模型组织到单独的包中 . 如果像我一样,您使用的Mongo数据库结构将单个集合分配给每个数据库(这是相当常见的)对于访问量很大的集合而言,这意味着每个数据模型必须位于自己的包中 . 这些包中的每一个都必须由 @EnableMongoRepositories 注释指向,该注释还包含 mongoTemplateRef 属性的 mongoTemplateRef 属性 .

    我希望这可以帮助别人避免我试图完成应该是一个相当普通的Mongo集成的麻烦 .

    PS: Abandon all hope, those who seek to combine auditing with this configuration.

相关问题