Название единицы динамического сохранения JPA
Мне нужен способ динамически указать блок персистентности в EJB.
Упрощенный пример:
У меня есть приложение, использующее несколько баз данных в качестве хранилищ данных.
Каждое из хранилищ данных структурно одинаково.
В зависимости от подключения клиента к приложению мне нужно получить доступ к данным из
конкретное хранилище данных.
Поэтому я хотел бы использовать тот же EJB, чтобы бизнес-логика не дублировалась,
но затем просто выберите правильный блок постоянного хранения на основе клиента.
До этого момента я только непосредственно ввел администратор сущности с жестким кодированием имени единицы сохранения.
Есть ли способ, которым я могу динамически внедрить диспетчер сущности с требуемым модулем постоянства, прикрепленным к EJB?
Кроме того, можно ли динамически добавлять единицы персистентности во время выполнения?
В настоящее время я должен указать блок персистентности в файле persistence.xml.
В идеале я хотел бы создавать пулы на сервере jdbc/db1, jdbc/db2 и т.д., Как требуется во время работы системы. Затем просто добавьте их в центральную клиентскую базу данных и привяжите ее к клиенту, чтобы при подключении клиента он проверял имя пула и использовал его при вызове EJB для получения единицы сохранения.
Я по-прежнему новичок в разработке Java EE. Любая помощь будет принята с благодарностью.
Ответы
Ответ 1
В текущей версии JPA, к сожалению, невозможно динамически создавать единицы сохранения. Если эта функциональность важна для вас, вы можете подумать о создании JIRA-проблемы для нее в трекерном вопросе JPA: http://java.net/jira/browse/JPA_SPEC
Используя аннотацию @PersistenceContext
, также невозможно динамически выбирать конкретный блок сохранения. На самом деле это область осколков, которую Hibernate когда-то пытался адресовать, но затем внезапно прекратил свое существование. См. http://www.hibernate.org/subprojects/shards.html
Есть несколько вещей, которые вы могли бы сделать, чтобы получить аналогичный эффект.
Один из подходов состоит в том, чтобы создать безгражданный EJB/CDI factory bean, который вы вводите всеми менеджерами сущностей. Стоимость этого является предельной, поскольку эти beans будут объединены, а менеджеры сущностей не так дороги, чтобы быть созданными в первую очередь.
Если вы также хотите ввести их на основе какого-либо условия, это условие должно быть доступно из контекста или должно быть указано в точке инъекции (но если вы это сделаете, вы могли бы также правый менеджер объектов).
Пример запуска:
@Stateless
@TransactionAttribute(SUPPORTS)
public class ShardingEntityManagerFactory {
@Resource
private SessionContext sessionContext;
@PersistenceContext(unitName = "pu1")
private EntityManager entityManager1;
@PersistenceContext(unitName = "pu2")
private EntityManager entityManager2;
@Produces @TransactionScoped @ShardedPersistenceContext
public EntityManager getEntityManager() {
if (sessionContext.isCallerInRole("FOO")) {
return entityManager1;
} else {
return entityManager2;
}
}
}
И затем в beans:
@Stateless
public class SomeBean {
@Inject @ShardedPersistenceContext
private EntityManager entityManager;
// ...
}
Обратите внимание, что вам понадобится Seam Persistence для аннотации @TransactionScoped
. Это также может быть проще, но немного более подробным, чтобы забыть о том, как вводить администратор сущности прозрачно и вводить ShardingEntityManagerFactory
вместо этого и получать из него вручную.
Ответ 2
Это, вероятно, не поможет решить проблему, но вам может показаться, что такие проблемы обсуждаются для реализации JPA 2.1
Это звучит как один из тех случаев многозадачности:
Предложение поддержки многопользовательской поддержки в JPA 2.1 JSR-338
Ответ 3
Для этого можно использовать один и тот же блок персистентности. Вам просто нужно предоставить карту свойств, когда вы вызываете createEntityManagerFactory() с url/datasource, который хотите использовать.
Ответ 4
Просто идея, не уверен, что это поможет:
Вы можете открыть inputStream для чтения файла persistence.xml
и заменить эти строки:
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/agendasccv2?zeroDateTimeBehavior=convertToNull"/>
<property name="javax.persistence.jdbc.password" value="btxbtxbtx"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="root"/>
Затем запустите экран конфигурации подключения, в котором пользователь входит в систему, и установите соединение в соответствии с правами пользователя в этом файле, затем запустите основное приложение
Не уверен, что это поможет, это просто и идея.
Зависит от вашего приложения и бизнес-логики.