JavaEE6: как выбрать единицу сохранения для диспетчера сущностей по информации для входа

мне нужно выбрать EntityManager в моем проекте JavaEE6 (JBoss7) в зависимости от сеанса входа в систему. Пользователь "Peter" приведет к использованию базы данных dbPeter, а пользователь "Paul" приведет к использованию базы данных dbPaul.

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

Я использую CDI для внедрения EntityManager. Итак, мой первый шаг — создать производителя для EntityManager, который ищет информацию для входа в сеанс и выбирает базу данных. Итак, как мне выбрать контекст базы данных/постоянства в этом prducer?? Начиная с Jboss7, я больше не вижу никакой записи jndi для модуля сохраняемости, поэтому поиск jndi не может быть рассмотрен.

я пытался использовать

@Produces
public EntityManager produceEM() {
    EntityManagerFactory managerFactory = Persistence.createEntityManagerFactory( "dbPaul" );

    return managerFactory.createEntityManager();
}

но это не удается во время развертывания с

HHH000231: Ошибка экспорта схемы: java.sql.SQLException: Вы не можете установить автоматическую фиксацию во время управляемой транзакции!

Это нормально, потому что место, где вводится em, в основном находится внутри транзакции. У кого-нибудь есть идея?


person martin    schedule 06.12.2011    source источник


Ответы (2)


Во-первых, я бы не хотел создавать EntityManagerFactory на лету. Я полагаю, вам придется делать это при каждом создании экземпляра DAO (или любого другого объекта EJB, который вы используете для доступа к своей базе данных). Если это так, подумайте дважды: создание EntityManagerFactory очень дорого и обычно должно выполняться один раз за жизненный цикл приложения. В качестве альтернативы я бы, вероятно, создал разные DAO для каждой единицы персистентности, перенеся ответственность за использование того или другого на верхний уровень, чтобы вы по-прежнему могли полагаться на контейнер для создания EntityManager.

При этом в вашем контексте и при условии, что метод productEM() находится в EJB, и вы используете безопасность, управляемую контейнером, вы можете внедрить EJBContext через:

@Resource
EJBContext ejbContext;

Отсюда вы можете получить Principal и создать свой EntityManager в зависимости от него.

Если какое-либо из предположений неверно, дайте мне знать, и я постараюсь обновить свой ответ.

ОТРЕДАКТИРОВАНО:

@Stateless
public class EntityManagerService {

   @Resource
   EJBContext ejbContext;

   @Produces
   public EntityManager produceEM() {

   EntityManagerFactory managerFactory = Persistence.createEntityManagerFactory(ejbContext.getCallerPrincipal().getName());

   return managerFactory.createEntityManager();

   }
}

Вы также можете создать свое собственное сопоставление между именами пользователей и именами баз данных, что, вероятно, является хорошей идеей, если вы хотите, чтобы между ними была какая-то развязка.

person Gonzalo Garcia Lasurtegui    schedule 06.12.2011
comment
Что ж, вы правы насчет EntityManagerFactory. В моем случае я не знаю, сколько единиц персистентности будет в производственной среде. У нас есть база данных для каждого клиента, но только одно развернутое веб-приложение. Таким образом, количество клиентов будет увеличиваться, и я очень-очень уверен, что операционная система не будет создавать DAO для каждого нового клиента =). Что мне нужно, так это общий способ привязки EntityManager к единице постоянства, где основная информация указывает на используемую единицу постоянства. - person martin; 06.12.2011
comment
Это не решает мою проблему с SQLException. Он по-прежнему говорит java.sql.SQLException: вы не можете установить автоматическую фиксацию во время управляемой транзакции! - person martin; 07.12.2011

Не совсем ответ на ваш вопрос, но рассматривали ли вы мультиарендность JPA? Насколько я знаю, Hibernate и EclipseLink поддерживают это.

person Tassos Bassoukos    schedule 06.12.2011
comment
Спасибо за подсказку, но это наоборот =) Мне нужна база данных для каждого клиента. Так хочет мой босс - person martin; 07.12.2011
comment
Этот парень показывает, как делать то, что вы хотите в Hibernate: relation.to/Bloggers/MultitenancyInHibernate . По сути, ConnectioProvider, который учитывает ваши назначения БД. Похоже, вам понадобится другой блок сохраняемости для вашей информации о пользователе, вам нужно будет как можно скорее установить идентификатор клиента, и если вы выполняете вызовы между потоками или между виртуальными машинами, у вас могут возникнуть проблемы. - person Tassos Bassoukos; 07.12.2011