Spring-data-mongodb连接到一个Mongo实例中的多个数据库

我使用的是最新的spring-data-mongodb(1.1.0.M2)和最新的Mongo Driver(2.9.0-RC1)。 我有一种情况,我有多个客户端连接到我的应用程序,我想在同一个Mongo服务器中给每个客户端自己的“架构/数据库”。 如果我直接使用驱动程序,这不是一项非常困难的任务:

Mongo mongo = new Mongo( new DBAddress( "localhost", 127017 ) ); DB client1DB = mongo.getDB( "client1" ); DBCollection client1TTestCollection = client1DB.getCollection( "test" ); long client1TestCollectionCount = client1TTestCollection.count(); DB client2DB = mongo.getDB( "client2" ); DBCollection client2TTestCollection = client2DB.getCollection( "test" ); long client2TestCollectionCount = client2TTestCollection.count(); 

看,很容易。 但是spring-data-mongodb不允许使用多个数据库的简单方法。 设置与Mongo的连接的首选方法是扩展AbstractMongoConfiguration类:

您将看到重写以下方法:

 getDatabaseName() 

因此它强制您使用一个数据库名称。 然后构建的存储库接口使用传递到SimpleMongoRepository类的MongoTemplate中的数据库名称。

我到底在哪里粘贴多个数据库名称? 我必须创建多个数据库名称,多个MongoTempate (每个数据库名称一个)和多个其他配置类。 而且仍然没有让我的存储库接口使用正确的模板。 如果有人尝试过这样的事情让我知道。 如果我搞清楚,我会在这里发布答案。

谢谢。

以下是我认为您正在寻找的文章的链接http://michaelbarnesjr.wordpress.com/2012/01/19/spring-data-mongo/

关键是提供多个模板

为每个数据库配置模板。

     

为每个数据库配置模板。

         

现在,你需要告诉Spring你的存储库在哪里它可以注入它们。 它们必须都在同一目录中。 我试图将它们放在不同的子目录中,但它无法正常工作。 所以它们都在存储库目录中。

      

每个存储库都是一个接口,编写如下(是的,您可以将它们留空):

 @Repository public interface ImageRepository extends MongoRepository { } @Repository public interface TruckRepository extends MongoRepository { } 

私有变量imageRepository的名称是集合! Image.java将保存到imagedb数据库中的图像集合中。

以下是查找插入删除记录的方法:

 @Service public class ImageService { @Autowired private ImageRepository imageRepository; } 

通过自动assembly,您可以将变量名称与配置中的名称(id)相匹配。

您可能希望子类SimpleMongoDbFactory并策略如何返回getDb返回的默认DB。 一种选择是使用线程局部变量来决定要使用的Db,而不是使用多个MongoTemplates。

像这样的东西:

 public class ThreadLocalDbNameMongoDbFactory extends SimpleMongoDbFactory { private static final ThreadLocal dbName = new ThreadLocal(); private final String defaultName; // init in c'tor before calling super // omitted constructor for clarity public static void setDefaultNameForCurrentThread(String tlName) { dbName.set(tlName); } public static void clearDefaultNameForCurrentThread() { dbName.remove(); } public DB getDb() { String tlName = dbName.get(); return super.getDb(tlName != null ? tlName : defaultName); } } 

然后,覆盖从AbstractMongoConfiguration扩展的@Configuration类中的mongoDBFactory() ,如下所示:

 @Bean @Override public MongoDbFactory mongoDbFactory() throws Exception { if (getUserCredentials() == null) { return new ThreadLocalDbNameMongoDbFactory(mongo(), getDatabaseName()); } else { return new ThreadLocalDbNameMongoDbFactory(mongo(), getDatabaseName(), getUserCredentials()); } } 

在您的客户端代码(可能是ServletFilter或其他类似代码)中,您需要在执行任何Mongo工作之前调用: ThreadLocalDBNameMongoRepository.setDefaultNameForCurrentThread()然后在完成后使用: ThreadLocalDBNameMongoRepository.clearDefaultNameForCurrentThread()重置它。

因此,经过大量的研究和实验,我得出的结论是,目前的spring-data-mongodb项目尚不可能。 我尝试了上面的baja方法并遇到了一个特定的障碍。 MongoTemplate从其构造函数中运行其ensureIndexes()方法。 此方法调出数据库以确保数据库中存在带注释的索引。 当Spring启动时, MongoTemplate的构造MongoTemplate被调用,所以我甚至没有机会设置ThreadLocal变量。 我必须在Spring启动时设置一个默认值,然后在请求进入时更改它。这是不允许的,因为我不想要也没有默认数据库。

一切都没有丢失。 我们最初的计划是让每个客户端在自己的应用服务器上运行,指向MongoDB服务器上自己的MongoDB数据库。 然后我们可以提供-Dprovider=系统变量,每个服务器只运行一个数据库。

我们被指示有一个多租户应用程序,因此尝试ThreadLocal变量。 但由于它不起作用,我们能够以我们最初设计的方式运行应用程序。

我相信有一种方法可以使这一切工作,它只需要比其他post中描述的更多。 您必须创建自己的RepositoryFactoryBean 。 以下是Spring Data MongoDB参考文档中的示例。 您仍然需要实现自己的MongoTemplate并延迟或删除ensureIndexes()调用。 但是你必须重写几个类来确保你的MongoTemplate被调用而不是Spring's 。 换句话说,做了很多工作。 我希望看到的工作发生甚至做,我只是没有时间。

谢谢你的回复。

要查看的是MongoDbFactory接口。 它的基本实现需要一个Mongo实例,并在整个应用程序生命周期中使用它。 要实现每线程(以及每个请求)数据库的使用,您可能必须实现AbstractRoutingDataSource的某些function。 这个想法几乎就是你有一个模板方法,它必须每次调用查找一个租户( ThreadLocal绑定我猜)然后从一组预定义的一个或一些自定义逻辑中选择一个Mongo实例来提出一个新的实例新租客等

请记住, MongoDbFactory通常通过getDb()方法使用。 但是,MongoDB中有一些function需要我们提供getDb(String name)DBRef (就像关系世界中的外键一样)可以指向文档完全不同的数据库。 因此,如果您正在执行委派,要么避免使用该function(我认为DBRef指向另一个DB是调用getDb(name)的唯一位置)或显式处理它。

从配置的角度来看,你可以简单地完全覆盖mongoDbFactory()或者根本不扩展基类,并提出自己的基于Java的配置。

我使用java Config使用了不同的数据库,这是我做的方式:

 @Bean public MongoDbFactory mongoRestDbFactory() throws Exception { MongoClientURI uri=new MongoClientURI(environment.getProperty("mongo.uri")); return new SimpleMongoDbFactory(uri); } @Override public String getDatabaseName() { return "rest"; } @Override public @Bean(name = "secondaryMongoTemplate") MongoTemplate mongoTemplate() throws Exception{ //hay que cambiar el nombre de los templates para que el contendor de beans sepa la diferencia return new MongoTemplate(mongoRestDbFactory()); } 

而另一个是这样的:

 @Bean public MongoDbFactory restDbFactory() throws Exception { MongoClientURI uri = new MongoClientURI(environment.getProperty("mongo.urirestaurants")); return new SimpleMongoDbFactory(uri); } @Override public String getDatabaseName() { return "rest"; } @Override public @Bean(name = "primaryMongoTemplate") MongoTemplate mongoTemplate() throws Exception{ return new MongoTemplate(restDbFactory()); } 

因此,当我需要更改我的数据库时,我只选择要使用的配置

据我所知,您希望在动态更改当前数据库时具有更大的灵活性。

我已经以一种简单的方式链接了一个实现多租户的项目。

它可以用作应用程序的起点。

它实现SimpleMongoDbFactory并提供自定义getDB方法来解析在特定时刻使用的正确数据库。 它可以通过多种方式进行改进,例如,通过从SpringSession对象中检索HttpSession中的db详细信息,例如可以由Redis缓存。

要同时使用不同的dbs使用不同的mongoTemplates,可能会将mongoDbFactory的范围更改为session。

参考文献:

多租户-弹簧- mongodb的