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 не позволяет легко использовать несколько баз данных. Предпочтительный способ настройки подключение к Mongo
расширения AbstractMongoConfiguration класс:
вы увидите, что вы переопределить следующий метод:
getDatabaseName()
так это заставляет вас использовать одно имя базы данных. Интерфейсы репозитория, которые вы затем создаете, используют это имя базы данных внутри MongoTemplate, которое передается в SimpleMongoRepository
класса.
где на земле я бы вставил несколько имен базы данных? Я должен сделать несколько имен базы данных, несколько MongoTempate
s (по одному на имя базы данных) и несколько других классов конфигурации. И это все еще не заставляет мои интерфейсы репозитория использовать правильный шаблон. Если кто-нибудь пробовал такое, дайте мне знать. Если я это выясню, я опубликую ответ здесь.
спасибо.
6 ответов
вот ссылка на статью, я думаю, это то, что вы ищете 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
- это коллекция! изображения.java будет сохранен в коллекцию изображений в базе данных imagedb.
здесь вы можете найти, вставить и удалить отчеты:
@Service
public class ImageService {
@Autowired
private ImageRepository imageRepository;
}
С помощью Autowiring вы сопоставляете имя переменной с именем (id) в вашей конфигурации.
вы можете захотеть подкласс SimpleMongoDbFactory
и выработать стратегию, как БД по умолчанию, как возвращается getDb
возвращается. Один из вариантов-использовать локальные переменные потока для выбора используемой БД вместо использования нескольких MongoTemplates.
что-то вроде этого:
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()
в своем @Configuration
класс, который простирается от AbstractMongoConfiguration
вот так:
@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()
после того как вы сделали.
Итак, после долгих исследований и экспериментов, я пришел к выводу, что это не возможно с текущей . Я попробовал метод Байи выше и столкнулся с определенным препятствием. The MongoTemplate
работает ensureIndexes()
метод из своего конструктора. Этот метод вызывает базу данных, чтобы убедиться, что аннотированные индексы существуют в базе данных. Конструктор для MongoTemplate
вызывается, когда Spring
запускается, поэтому у меня даже нет возможности установить ThreadLocal
переменной. Мне надо по умолчанию уже установлено, когда Spring
начинается, затем измените его, когда придет запрос. Это недопустимо, потому что я не хочу и у меня нет базы данных по умолчанию.
однако не все было потеряно. Наш первоначальный план состоял в том, чтобы каждый клиент работал на своем собственном сервере приложений, указывая на свой собственный
место, чтобы посмотреть на это MongoDbFactory
интерфейс. Основная реализация этого принимает экземпляр Mongo и работает с ним на протяжении всего срока службы приложения. Чтобы добиться использования базы данных для каждого потока (и, следовательно, для каждого запроса), вам, вероятно, придется реализовать что-то вроде AbstractRoutingDataSource. Идея заключается в том, что у вас есть метод шаблона, который должен будет искать арендатора для вызова (ThreadLocal
Баунд, я думаю), а затем выберите Mongo
экземпляр из набора стандартных или пользовательскую логику, чтобы придумать новый для нового арендатора и т. д.
имейте в виду, что MongoDbFactory
обычно get используется через getDb()
метод. Тем не менее, в MongoDB есть функции, которые нам нужно предоставить getDb(String name)
. DBRef
s (sth. как внешний ключ в реляционном мире) может указывать на документы совершенно другой базы данных. Поэтому, если вы делаете делегирование, либо избегайте использования этой функции (я думаю, что DBRef
s указание на другую БД-единственные места, вызывающие 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());
}
поэтому, когда мне нужно изменить мою базу данных, я только выбираю, какую конфигурацию использовать
насколько я понимаю, вы хотите больше гибкости в изменении текущей БД на лету.
Я связал проект, который реализует multi tenancy простым способом.
Он может быть использован в качестве отправной точки для приложения.
он реализует SimpleMongoDbFactory и предоставляет пользовательский метод getDB для разрешения правильной БД для использования в определенный момент. Его можно улучшить многими способами, например, путем извлечения сведений о БД из HttpSession из Объект SpringSession, который, например, может быть кэширован Redis .
чтобы иметь разные mongoTemplates, используя разные dbs одновременно, возможно, измените область вашего mongoDbFactory на сеанс.
ссылки: