26

最新の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()

したがって、1つのデータベース名を使用する必要があります。次に構築するリポジトリインターフェイスは、SimpleMongoRepositoryクラスに渡されるMongoTemplate内のデータベース名を使用します。

いったいどこに複数のデータベース名を付けるのでしょうか?複数のデータベース名、複数MongoTempateのs(データベース名ごとに1つ)、および他の複数の構成クラスを作成する必要があります。それでも、リポジトリインターフェイスで正しいテンプレートを使用することはできません。誰かがそのようなことを試みたなら、私に知らせてください。私がそれを理解したら、私はここに答えを投稿します。

ありがとう。

4

6 に答える 6

14

これがあなたが探しているものだと思う記事へのリンクです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> {

}

プライベート変数の名前はimageRepositoryコレクションです!Image.javaは、imagedbデータベース内の画像コレクションに保存されます。

レコードの検索挿入削除の方法は次のとおりです。

@Service
public class ImageService {

    @Autowired
    private ImageRepository imageRepository;
}

自動配線により、変数名を構成内の名前(id)に一致させます。

于 2012-08-31T21:14:35.683 に答える
9

spring-data-mongodbしたがって、多くの調査と実験の結果、これは現在のプロジェクトではまだ可能性がないと結論付けました。上記のバハの方法を試してみたところ、特定のハードルに遭遇しました。は、コンストラクター内からメソッドをMongoTemplate実行します。ensureIndexes()このメソッドはデータベースを呼び出して、注釈付きインデックスがデータベースに存在することを確認します。のコンストラクターは起動MongoTemplate時に呼び出されるため、変数を設定する機会すらありません。起動時にデフォルトを設定しておき、リクエストが届いたときに変更する必要があります。デフォルトのデータベースが必要ないため、これは許可されていません。SpringThreadLocalSpring

しかし、すべてが失われたわけではありません。私たちの当初の計画は、各クライアントを独自のアプリケーションサーバーで実行し、サーバーMongoDB上の独自のデータベースを指すようにすることMongoDBでした。次に、-Dprovider=システム変数を指定すると、各サーバーは1つのデータベースのみをポイントして実行されます。

マルチテナントアプリケーションを使用するように指示されたため、ThreadLocal変数を試してみました。しかし、それが機能しなかったため、最初に設計した方法でアプリケーションを実行することができました。

これをすべて機能させる方法はあると思いますが、他の投稿で説明されている以上のことが必要です。あなたはあなた自身を作らなければなりませんRepositoryFactoryBean。これは、SpringDataMongoDBリファレンスドキュメントの例です。それでも、独自の実装を行い、呼び出しMongoTemplateを遅延または削除する必要がありensureIndexes()ます。MongoTemplateただし、の代わりに自分が呼び出されるようにするには、いくつかのクラスを書き直す必要がありますSpring's。言い換えれば、多くの作業です。実現したい、あるいはやりたいと思っている仕事は、時間がありませんでした。

回答ありがとうございます。

于 2012-10-09T15:17:55.043 に答える
9

SimpleMongoDbFactoryによって返されるデフォルトのDBがどのように返されるかをサブクラス化して戦略化することができますgetDb。1つのオプションは、複数のMongoTemplatesを使用する代わりに、スレッドローカル変数を使用して使用するDbを決定することです。

このようなもの:

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など)で ThreadLocalDBNameMongoRepository.setDefaultNameForCurrentThread() 、Mongoの作業を行う前に:を呼び出し、その後、 ThreadLocalDBNameMongoRepository.clearDefaultNameForCurrentThread() 完了後に:でリセットする必要があります。

于 2012-08-22T22:56:57.403 に答える
4

注目すべき点はMongoDbFactoryインターフェースです。その基本的な実装はMongoインスタンスを取り、アプリケーションの全存続期間を通じてそれと連携します。スレッドごと(したがってリクエストごと)のデータベースの使用を実現するには、 AbstractRoutingDataSourceの行に沿って何かを実装する必要があります。アイデアは、呼び出しごとにテナントを検索し(ThreadLocalバインドされていると思います)、Mongo事前定義されたインスタンスまたはカスタムロジックのセットからインスタンスを選択して、新しいインスタンスを作成する必要があるテンプレートメソッドがあるということです。テナント等

MongoDbFactory通常はgetDb()メソッドを介して使用されることに注意してください。ただし、MongoDBには、を提供する必要のある機能がありますgetDb(String name)DBRefs(sth。リレーショナル世界の外部キーのように)は、まったく異なるデータベースのドキュメントを指すことができます。DBRefしたがって、委任を実行している場合は、その機能の使用を避けるか(別のDBを指すsだけが呼び出す場所だと思いますgetDb(name))、または明示的に処理します。

構成の観点からは、単純mongoDbFactory()に完全にオーバーライドするか、基本クラスをまったく拡張せずに、独自のJavaベースの構成を考え出すことができます。

于 2012-08-23T16:23:48.827 に答える
1

私はjavaConfigを使用して別のDBを使用しました、これは私がそれをした方法です:

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

そしてもう1つは次のようなものでした:

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

したがって、データベースを変更する必要がある場合は、使用する構成を選択するだけです。

于 2015-09-24T18:06:19.240 に答える
-2

私が理解している限り、現在のデータベースをその場で変更する際の柔軟性を高めたいと考えています。

マルチテナンシーを簡単な方法で実装するプロジェクトをリンクしました。

これは、アプリケーションの開始点として使用できます。

SimpleMongoDbFactoryを実装し、特定の瞬間に使用する正しいデータベースを解決するためのカスタムgetDBメソッドを提供します。これは多くの方法で改善できます。たとえば、SpringSessionオブジェクトのHttpSessionからデータベースの詳細を取得することで改善できます。たとえば、Redisによってキャッシュされる可能性があります。

異なるデータベースを同時に使用する異なるmongoTemplatesを使用するには、mongoDbFactoryのスコープをセッションに変更します。

参照:

multi-tenant-spring-mongodb

于 2017-03-27T11:32:43.187 に答える