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

我正在使用最新的spring-data-mongodb(1.1.0.M2)和最新的Mongo驱动程序(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不允许使用多个数据库的简单方法。设置连接的首选方法是扩展 AbstractMongoConfiguration 类:Mongo

您将看到您重写了以下方法:

getDatabaseName()

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

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

谢谢。


答案 1

这是一篇文章的链接,我认为这是你正在寻找的 http://michaelbarnesjr.wordpress.com/2012/01/19/spring-data-mongo/

关键是提供多个模板

为每个数据库配置一个模板。

<bean id="vehicleTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    <constructor-arg ref="mongoConnection"/>
    <constructor-arg name="databaseName" value="vehicledatabase"/>
</bean>

为每个数据库配置一个模板。

<bean id="imageTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <constructor-arg ref="mongoConnection"/>
        <constructor-arg name="databaseName" value="imagedatabase"/>
</bean>

<bean id="vehicleTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    <constructor-arg ref="mongoConnection"/>
    <constructor-arg name="databaseName" value="vehicledatabase"/>
</bean>

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

<mongo:repositories base-package="my.package.repository">
    <mongo:repository id="imageRepository" mongo-template-ref="imageTemplate"/>
    <mongo:repository id="carRepository" mongo-template-ref="vehicleTemplate"/>
    <mongo:repository id="truckRepository" mongo-template-ref="vehicleTemplate"/>
</mongo:repositories>

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

@Repository
public interface ImageRepository extends MongoRepository<Image, String> {

}

@Repository
public interface TruckRepository extends MongoRepository<Truck, String> {

}

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

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

@Service
public class ImageService {

    @Autowired
    private ImageRepository imageRepository;
}

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


答案 2

您可能希望对返回的默认 DB 的返回方式进行子类化和策略化。一种选择是使用线程局部变量来决定要使用的数据库,而不是使用多个MongoTemplates。SimpleMongoDbFactorygetDb

像这样:

public class ThreadLocalDbNameMongoDbFactory extends SimpleMongoDbFactory {
    private static final ThreadLocal<String> dbName = new ThreadLocal<String>();
    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);
    }
}

然后,在类中重写,该类从以下方式扩展:mongoDBFactory()@ConfigurationAbstractMongoConfiguration

@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()