2013-05-01 4 views
9

В post прошлом августе sbzoom предложил решение сделать весенне-данные MongoDB многопользовательским:.Создание пружинных данных MongoDB многопользовательских

«Вы должны сделать свой собственный RepositoryFactoryBean Вот пример из Spring Data MongoDB Reference Docs. Вам все равно придется реализовать свой собственный MongoTemplate и задержать или удалить вызов securityIndexes(). Но вам придется переписать несколько классов, чтобы убедиться, что ваш MongoTemplate вызывается вместо Spring. »

Неужели кто-то реализует это или что-то подобное?

ответ

13

Существует множество способов кошки здесь. По сути, все сводится к тому, на каком уровне вы хотели бы применить арендную плату.

Основы

Основной подход заключается в связывании какой-то ключ, идентифицирующий клиента на основе каждого потока, так что вы можете узнать о клиенте текущий поток исполнения сделок с. Обычно это достигается путем заполнения ThreadLocal с помощью некоторой информации, связанной с проверкой подлинности, поскольку вы обычно можете получить арендатора от зарегистрированного пользователя.

Теперь, если это на месте, есть несколько вариантов использования знаний арендатора. Позвольте мне кратко изложить наиболее распространенные из них:

Multi-аренда на уровне базы данных

Один из способов разделения данных для нескольких клиентов, чтобы иметь отдельные базы данных для каждого арендатора. Spring Data. Основная абстракция MongoDB для этого - интерфейс MongoDBFactory. Самый простой способ - переопределить SimpleMongoDbFactory.getDb(String name) и вызвать родительский метод с именем базы данных, например. обогащенный префиксом арендатора или тому подобное.

Multi-аренды на уровне сбора

Другим вариантом является арендатором определенных коллекций, например, через предварительные или постфиксные документы арендатора. Этот механизм можно использовать с помощью языка Spring Expression (SpEl) в атрибуте @Document аннотации collectionName. Во-первых, разоблачать префикс арендатора через Spring бина:

@Component("tenantProvider") 
public class TenantProvider { 

    public String getTenantId() { 
    // … implement ThreadLocal lookup here 
    } 
} 

Затем использовать SPEL в ваших доменных типов @Document отображение:

@Document(collectionName = "#{tenantProvider.getTenantId()}_accounts" 
public class Account { … } 

SPEL позволяет обращаться к пружине фасолью по имени и выполнять методы на них , MongoTemplate (и, следовательно, абстракция репозитория транзитивно) будут использовать метаданные отображения класса документа, а подсистема сопоставления будет оценивать атрибут collectionName, чтобы узнать о коллекции, с которой нужно взаимодействовать.

+1

Большое спасибо за быстрый ответ Оливер. Мы уже решили перейти к первому подходу - уровню базы данных. sbzoom вызвал у него озабоченность: «MongoTemplate запускает свой метод verifyIndexes() из своего конструктора. Этот метод вызывает базу данных, чтобы убедиться, что в базе данных есть аннотированные индексы.Конструктор для MongoTemplate вызывается, когда Spring запускается, поэтому у меня даже нет возможности установить переменную ThreadLocal ». Какая работа вокруг этого? – nicolasvdb

+1

@Oliver для многопользовательской аренды на уровне сбора, возникла бы проблема, индексы не будут созданы при запуске для коллекций? Будет ли это делать по запросу? – robinhowlett

+0

Но как shpuld работает с '' 'MongoRepositories''', им нужно создать' '' MongoTemplate''' во время создания. хотел бы иметь некоторое сопоставление, например '' '' '' для моих целей, но как это реализовать? – Zarathustra

2

У меня был аналогичный подход к Оливеру Гирке. По крайней мере, на уровне базы данных. https://github.com/Loki-Afro/multi-tenant-spring-mongodb Вы должны быть в состоянии сделать что-то вроде этого:

 MultiTenantMongoDbFactory.setDatabaseNameForCurrentThread("test"); 
     this.personRepository.save(createPerson("Phillip", "Wirth", ChronoUnit.YEARS.between(
       LocalDate.of(1992, Month.FEBRUARY, 3), 
       LocalDate.now()))); 

     System.out.println("data from test: " + this.personRepository.findAll()); 
//  okay? fine. - lets switch the database 
     MultiTenantMongoDbFactory.setDatabaseNameForCurrentThread("test666"); 

//  should be empty 
     System.out.println("data from test666: " + this.personRepository.findAll()); 
Смежные вопросы