2014-01-15 4 views
6

Что происходит, когда используются следующие программные транзакции и идиома сеанса с CMT (EJB3) и Hibernate Core для использования CMT?
Принято считать, требуется текущая транзакция СМТ и начали использовать по умолчанию @TransactionAttribute(REQUIRED)Hibernate - CMT EJB с использованием программной транзакции idiom

  1. Будет ли транзакция зимуют присоединиться к текущей CMT на beginTransaction()?
  2. Будет ли commit() попытаться совершить транзакцию спящего режима немедленно или дождаться завершения текущего CMT?
  3. Что происходит при закрытии сеанса в CMT?

B. Поведение зависит от того, связана ли текущая сессия с CMT с использованием getCurrentSession()?

// A: openSession() 
// B: getCurrentSession(); 
Session session = sessionFactory.openSession(); 
Transaction tx = null; 
try 
{ 
    tx = session.beginTransaction(); 

    // do some work 

    tx.commit(); 
} 
catch (final RuntimeException e) 
{ 
    try 
    { 
     tx.rollback(); 
    } 
    catch (final RuntimeException e) 
    { 
     // log error 
    } 
    throw e; 
} 
finally 
{ 
    session.close(); 
} 

В моем приложении в настоящее время я использую одну базу данных, и она работала отлично с помощью программных операций JDBC с Hibernate. Теперь приложение также использует JMS-Queue for Mail messaging и хочет объединить его в глобальную транзакцию CMT.

Edit:

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

конфигурации Hibernate hibernate.cfg.xml для включения СМТ:

Hibernate 4.2.6 и Glassfish 3.1.2

<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> 
<property name="hibernate.connection.autocommit">false</property> 
<property name="hibernate.connection.datasource">jdbc/datasource</property> 
<property name="hibernate.current_session_context_class">jta</property> 
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.CMTTransactionFactory</property> 
<property name="hibernate.transaction.jta.platform">org.hibernate.service.jta.platform.internal.SunOneJtaPlatform</property> 

SessionFactory поиска

SessionFactory построен в пределах одноэлементный EJB. Снял ненужные вещи.

@Startup 
@Singleton 
public class SessionManager 
{ 
    private SessionFactory sessionFactory; 

    public SessionManager() 
    { 
     final Configuration configuration = new Configuration().configure(); 
     this.sessionFactory = configuration.buildSessionFactory(); 
    } 
} 

ответ

1

Как отметил Лук, это не способ закодировать его в среде CMT. Во всяком случае, часть безопасна здесь согласно http://docs.jboss.org/hibernate/annotations/3.5/api/org/hibernate/Session.html#beginTransaction%28%29, который говорит

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

tx.rollback() также безопасен. Это не указано в документе, но CMTTransaction фактически выполняет getTransaction().setRollbackOnly(), т. Е. Просто маркирует TX для отката. Конец фактически не передает TX, но может очистить сеанс. Реальная фиксация будет нарушать семантику транзакции, если задействовано более одного ресурса.

+0

Спасибо за ответ. Для меня описание 'session.beginTransaction()' было недостаточно ясным, какая транзакция имеет значение (Hibernate или JTA). – djmj

+0

http://docs.jboss.org/hibernate/annotations/3.5/api/org/hibernate/Transaction.html Кажется, он может быть как чистым, так и чистым jdbc, просто зависит от TransactionFactory – Gab

+0

В общем, да, но не в постановке вопроса (если вы не сконфигурировали свой TransactionFactory для этого случая). – Drunix

1

С CMT (Container Managed транзакции) вы ничего не объявлять как Тх = session.beginTransaction(); вы позволяете контейнеру выполнять свою работу за вас. Вы указываете только, когда и если контейнер поддерживает транзакции. Проверьте документ oracle doc Java EE 5 Tutorial

Допустим, у вас есть EJB, его объем транзакций по умолчанию обязательно. Таким образом, спящий режим будет фактически связан с этой областью транзакций.

Следующий пример с первой EJB, без операции, которая вызывает другой с СМТ:

@TransactionAttribute(NOT_SUPPORTED) 
@Stateful 
public class TransactionBean implements TransactionInterface{ 

    @EJB BusinessBean businessBean; 

    public method1(){ 
     businessBean.doSomething(); 
    } 
} 

@TransactionAttribute(REQUIRED) 
@Stateful 
public class BusinessBean implements BusinessInterface{ 

    @PersistenceContext(unitName = "some-persistence-unit") 
    private EntityManager entityManager; 

    public void doSomething(){ 
     Someclass entity = entityManager.finde(Someclass.class, 1) // Find entity with id 1 
     entity.setData("somedata"); 
    } 
} 

когда Methode йоЗотеЬЫпд() выполняется, контейнер будет вымывать и совершить обновление до databese с наружной В ejb нет транзакции. Это работает только если источник данных также снабжен контейнером

+0

'вы не объявляете ничего похожего на tx = session.beginTransaction()' Вот почему я спрашивал, что произойдет, если вы смешаете транзакцию с управлением с использованием CMT с программной обработкой транзакций, чтобы сохранить переносимый код. – djmj

0

сессионного (в JPA persistence context, который привязан к EntityManager примеру) является «в памяти» снимок состояния схемы базы данных подмножества. В зависимости от вашей конфигурации объем вашей сессии будет отличаться. В стандартном веб-приложении у вас будет один сеанс для каждого запроса.

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

Транзакция является единицей работы (в теории сессия тоже). Он связан с базовой системой транзакций RDBMS и привязан к сеансу, на котором он был открыт.

В контексте «диспетчер управляемых контейнеров» (то, что вы вызываете CMT), контейнер будет отвечать за привязку вашего сеанса к определенной области и распространять транзакции в соответствии с найденной аннотацией @Transactional при вызове методов.

На самом деле, что происходит: Ваш контейнер хранит экземпляр сеанса где-то и сможет предоставить его вашему экземпляру ejb, используя аннотацию @PersistenceContext. Вы вручную создаете новый экземпляр сеанса, используя sessionFactory.openSession(), открывая транзакцию и выполняете свои операции. Управляемый экземпляр сеанса не может видеть ни одну из этих изменений до тех пор, пока вы не совершите транзакцию, вручную покраснели или закрыли свой собственный сеанс и вручную активировали обновление на контейнере.

Метод getCurrentSession() - это механизм спящего режима, который действует как механизм управления областью сеанса контейнера в контексте Java SE (без контейнера). Я полагаю (но я понятия не имею о реализации спящего JPA), что он не вернет сеанс, управляемый контейнером, но я могу ошибаться в этом вопросе. (редактировать Я)

Здесь правильное решение будет для получения текущего контейнера управляемый экземпляр сеанса с помощью @PersistenceContext и управлять распространением транзакций с использованием @Transactional аннотацию.

См https://community.jboss.org/wiki/SessionsAndTransactions

См Luk anwser ниже

FYI См Container-Managed Transactions

EDIT (в соответствии с вопросом издание)

См Difference between a "jta-datasource" and a " resource-local " datasource?

На самом деле, кажется, я был эффективно неправильно и t вам не нужно использовать инкрементность контекста persistence из контейнера, но вы ДОЛЖНЫ использовать транзакции JTA.

В EJB 3.0 спецификации, раздел 13.3.4 Enterprise Beans Использование Container-Managed разграничении транзакций:

The enterprise bean’s business methods [...] must not attempt to obtain or use the javax.transaction.UserTransaction interface. 

Это означает, что вы можете использовать

sessionFactory.getCurrentSession() 

но вы не должны использовать Тх = сессия.BeginTransaction(), но вместо этого

@TransactionAttribute(TransactionAttributeType.REQUIRED) 

См Transaction размежевание с EJB/раздела КРТ в JBoss док выше

+0

Из вашего связанного документа jboss я не вижу, что я не должен его использовать. Или я пропустил это. Он указывает только на предложение (так же, как официальные документы спящего режима). Вместо того, чтобы кодировать начало, фиксацию и откат ваших транзакций в ваше приложение, вы можете использовать декларативный подход. « – djmj

+0

действительно нет ничего в документе jboss, который явно запрещает это Однако рекомендуется использовать декларативный подход. Если эффективный тип реализации, возвращаемый 'beginTransaction()', является 'CMTTransaction', ваш подход может работать. – Gab

+0

Я, наверное, слишком привязан к JPA, я не знал, что спящий режим был настолько гибким, что ваш вопрос отличный, и явно заслуживает большего интереса. – Gab

0

я узнал что-то новое из вашего вопроса, так как я не знаю, Hibernate может быть настроен таким образом (хотя было ясно, что он поддерживает JTA). В любом случае в соответствии с документацией, кажется, что вы не обязаны настроить его для того, чтобы использовать JTA, как описано here:

Если ваша настойчивость слой работает на сервере приложений (например, за EJB сессии бобы), каждое подключение к источнику данных, полученное Hibernate автоматически станет частью глобальной транзакции JTA. Вы также можете установить автономную реализацию JTA и использовать ее без EJB. Hibernate предлагает две стратегии интеграции JTA.

Также см. Примеры в документации, так как вам не нужно открывать транзакции в контексте CMT. Однако, если вы хотите контролировать демаркации транзакций, проверьте эти примеры BMT.

+1

Спасибо за ваш ответ. Теперь я тестировал и отлаживал его: транзакция hibernate, полученная 'beginTransaction()', имеет тип 'CMTTransaction' со статусом, установленным на' JOINED'. И он совершает возврат метода, когда транзакция контейнера также будет совершена. Я добавил точку останова прямо перед возвратом метода, чтобы проверить его. Используя связанный с контейнером jta сеанс через 'getCurrentSession(), наблюдается такое же поведение (исключая' session.close() ', так как контейнер закрывает его). Теперь я смущен. – djmj

+0

Hibernate 'CMTTransaction' имеет метод' join() ', чтобы присоединиться к нему с базовой транзакцией, но в моей настройке он по умолчанию соединен. – djmj

+0

Не могли бы вы показать нам, как вы получаете sesionFactory и конфигурацию persistence.xml/hibernate? –

Смежные вопросы