Название единицы динамического сохранения 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 вместо этого и получать из него вручную.

Ответ 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"/>

Затем запустите экран конфигурации подключения, в котором пользователь входит в систему, и установите соединение в соответствии с правами пользователя в этом файле, затем запустите основное приложение

Не уверен, что это поможет, это просто и идея. Зависит от вашего приложения и бизнес-логики.