JPA имя единицы динамической персистентности - PullRequest
15 голосов
/ 31 марта 2012

Мне нужен способ динамического указания единицы персистентности в EJB.

Упрощенный пример:

У меня есть приложение, использующее несколько баз данных в качестве хранилищ данных. Каждое из хранилищ данных структурно одинаково. В зависимости от клиента, подключающегося к приложению, мне нужен доступ к данным из конкретное хранилище данных.

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

До этого момента я только напрямую вводил диспетчер сущностей с жестко запрограммированным именем модуля персистентности. Есть ли способ, которым я могу динамически внедрить менеджер сущностей с необходимым модулем персистентности, присоединенным к EJB? Кроме того, можно ли динамически добавлять единицы сохранения во время выполнения? В настоящее время я должен указать единицу постоянства в файле persistence.xml. В идеале я хотел бы создавать пулы на сервере jdbc / db1, jdbc / db2 и т. Д. По мере необходимости во время работы системы. Затем просто добавьте их в базу данных центрального клиента и свяжите с клиентом, чтобы при подключении клиента он проверял имя пула и использовал его при вызове EJB для получения модуля персистентности.

Я все еще новичок в разработке Java EE. Любая помощь будет принята с благодарностью.

Ответы [ 4 ]

8 голосов
/ 31 марта 2012

В текущей версии JPA, к сожалению, динамическое создание единиц постоянства невозможно. Если эта функциональность важна для вас, вы можете рассмотреть вопрос о создании проблемы JIRA для нее в системе отслеживания проблем JPA: http://java.net/jira/browse/JPA_SPEC

Используя аннотацию @PersistenceContext, также невозможно динамически выбрать конкретную единицу сохранения. На самом деле это область шардинга, которую Hibernate однажды попытался решить, но затем внезапно прекратил. Смотри http://www.hibernate.org/subprojects/shards.html

Однако есть несколько вещей, которые вы могли бы сделать, чтобы получить подобный эффект.

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

Если вы также хотите внедрить их на основе какого-либо условия, тогда это условие должно быть доступно из контекста или должно быть указано в точке внедрения (но если вы сделаете это, вы можете также ввести Право менеджера организации напрямую).

Пример запуска:

@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;
        }
    }
}

А потом в твоих бобах:

@Stateless
public class SomeBean {

    @Inject @ShardedPersistenceContext
    private EntityManager entityManager;

    // ...
}

Обратите внимание, что для аннотации @TransactionScoped вам понадобится постоянство шва. Также было бы проще, но немного более многословно, забыть о прозрачном введении менеджера сущностей, вместо этого ввести ShardingEntityManagerFactory и получить из него нужный вручную.

3 голосов
/ 31 марта 2012

Это, вероятно, не поможет решить проблему, но вам может быть интересно узнать, что такого рода проблемы обсуждаются для реализации JPA 2.1

Это звучит как один из тех случаев мультитенантности:

Предложение по поддержке нескольких арендаторов в JPA 2.1 JSR-338

2 голосов
/ 17 сентября 2012

Для этого вы можете использовать ту же единицу постоянства.Вам просто нужно предоставить свойства Map при вызове createEntityManagerFactory () с источником URL / данных, который вы хотите использовать.

1 голос
/ 16 сентября 2012

Просто идея, не уверен, поможет ли это: вы можете открыть 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"/>

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

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

...