Вы определенно можете делать то, что просите, но демон в деталях.
Я бы назвал это JPA Multitenancy, а здесь - интересная статья, предоставленная случайным поиском, которая предлагает правильный метод с использованием CDI. Я начну с более общего подхода, принимая во внимание тот факт, что вам также потребуются дополнения во время выполнения новых арендаторов.
Обратите внимание, что Hibernate предлагает нативных решений для мультитенюса. Я не знаю, каким провайдером JPA вы пользуетесь, но я предполагаю, что другие имеют схожие функции.
Основы
Это должно быть сделано с использованием отдельных, специфичных для арендатора экземпляров EntityManagerFactory
. Точный URL-адрес соединения с БД может быть задан картой, переданной в Persistence.createEntityManagerFactory()
. Например, если существует META-INF/persistence.xml
, применяется следующий код:
HashMap props = new HashMap();
props.put("javax.persistence.jdbc.url", /* tenant-specific JDBC URL*/);
EntityManagerFactory tenantSpecificEntityManagerFactory =
Persistence.createEntityManagerFactory("name-of-persistence-unit-from-persistence.xml", props);
props
обычно переопределяет любые свойства, указанные в persistence.xml
. Возможно, достаточно переопределить только URL JDBC, может быть, вам потребуется переопределить имя пользователя / пароль или другие вещи. С этого момента вы можете получить специфичный для арендатора контекст персистентности и работать с ним:
EntityManager tenantSpecificEm = tenantSpecificEntityManagerFactory.createEntityManager();
Улов: Эффективность
Вы можете выполнять приведенный выше код каждый раз, когда вам нужен специфичный для арендатора EntityManager
(и затем также закрыть завод). Но это будет крайне неэффективно по следующим причинам:
- Создание
EntityManagerFactory
заново с каждым запросом происходит медленно
- Создание подключения к БД заново с каждым запросом происходит еще медленнее
Для решения этих проблем вам необходимо:
- Кэшировать
EntityManagerFactory
экземпляры
- Как-нибудь использовать пул соединений
Кэширование EntityManagerFactory
экземпляров
Я предполагаю, что существует надежный механизм для связи каждого запроса с соответствующим арендатором. Кроме того, вам потребуется Map
имя арендатора для соответствующего экземпляра EntityManagerFactory
. Как это хранится и используется, зависит от приложения, например, есть ли какая-либо структура внедрения зависимости? Первая ссылка имеет решение с CDI, аналогичные решения будут применяться для других контейнеров DI.
Пул соединений
Серверы приложений предлагают пул соединений с БД. Tomcat тоже. Серверы приложений могут позволить вам добавлять пулы соединений с БД во время выполнения без необходимости перезапуска сервера. Я не знаю, поддерживает ли используемая вами версия Tomcat (думаю, нет, но, пожалуйста, исправьте меня). Итак:
- Если сервер приложений (в данном случае Tomcat) поддерживает создание пула соединений во время выполнения, сделайте это и настройте
props
, чтобы использовать его
- В противном случае вам придется использовать пользовательский пул соединений, который применяется к каждому
EntityManagerFactory
. По крайней мере, в Hibernate есть эта функция .
Сохранить настройки
Полагаю, вы уже поняли это, но параметры, применяемые во время выполнения (клиенты, имя клиента и сопоставления свойств соединения), должны как-то сохраняться, чтобы они применялись повторно при перезапуске сервера. Это может быть файл конфигурации или другая база данных «администрирования».