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

时间:2016-06-28 21:04:49

标签: spring mongodb spring-data spring-data-mongodb

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

我已多次阅读文档,并通过代码搜索解决方案,但一无所获。当然这样一个广泛采用的项目对这个问题有一些解决方案吗?我目前的尝试看起来像这样:

QPair<double, bool> toDouble(QString in) {
  auto dots = in.count('.');
  auto commas = in.count(',');
  if ((dots > 1 && commas > 1) || (dots == 1 && commas ==1))
    // equivocal input
    return qMakePair(0.0, false);
  if (dots > 1 && commas <=1) {
    // dots are group separators
    in.replace(".", "");
    in.replace(',', '.');
  }
  else if (dots <= 1 && commas > 1) {
    // commas are group separators
    in.replace(",", "");
  }
  else if (commas == 1) {
    // assume commas are decimal points
    in.replace(',', '.');
  }
  bool ok;
  auto dbl = in.toDouble(&ok);
  return qMakePair(dbl, ok);
}

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

@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");
    }
}

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

@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");
    }
}

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

实际上,当我启动应用程序时,RegisteredCard存储库解析为MongoDB存储库实例,该实例具有绑定到TenantConfiguration数据库的关联@Repository public interface RegisteredCardRepository extends MongoRepository<RegisteredCard, Guid>, QueryDslPredicateExecutor<RegisteredCard> { } 。实际上,每个存储库都会收到相同的,不正确的MongoOperations对象。尽管每个存储库都有自己独特的配置,但似乎首先访问的数据库仍然是每个存储库的目标数据库。

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

1 个答案:

答案 0 :(得分:3)

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

  • @EnableMongoRepositories(basePackageClasses = Whatever.class)只是使用限定类名来指示它应扫描所有所定义数据模型的。如果@EnableMongoRepositories(basePackageClasses = "com.mypackage.whatevers")驻留在该包中,这完全等同于执行Whatever.class
  • @EnableMongoRepositories不可重复,但可用于注释多个类。其他SO对话已经涵盖了这一点,但在此重复。您需要定义几个存储库配置类; 您打算与之互动的每个数据库一个
  • 您的每个存储库配置都必须在MongoTemplate注释中指定自己的@EnableMongoRepositories实例。您只能提供一个Mongo bean,但MongoTemplate依赖于特定的MongoMappingContext
  • @EnableMongoRepositories注释有助于定义映射上下文,这可以理解数据模型的结构以及如何序列化它们。它还了解@Document@Field注释,并且可以解决持久存在的问题。 Mongo模板实例是您指定要与之交互的数据库的位置。因此,通过提供@EnableMongoRepositories注释以及basePackage属性和mongoTemplateRef属性,您可以告诉Spring Data Mongo“获取这些模型并将其保留在此特定数据库中”。

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

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

PS:放弃所有希望,那些寻求将审计与此配置相结合的人。