Hibernate-CMT EJB с использованием идиомы программной транзакции

что происходит, когда следующая программная транзакция и идиома сеанса используются в CMT (EJB3), а Hibernate Core настроен на использование CMT?
предполагается, что текущая транзакция CMT требуется и запускается с использованием default @TransactionAttribute(REQUIRED)

  1. будет ли транзакция hibernate присоединяться к текущему 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-очередь для обмена сообщениями и хочет объединить ее в глобальный CMT торговая операция.

Edit:

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

настройки спящего режима hibernate.cfg.xml для включения CMT:

спящий режим 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 строится внутри одноэлементного EJB. снял ненужные вещи.

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

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

4 ответов


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

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

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


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

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

С первых EJB С нет транзакция, которая вызывает другую с cmt:
@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 doSomething() будет сделано, контейнер сбросит и зафиксирует обновление в databese, так как внешний ejb не имеет запущенной транзакции. Это работает только в том случае, если источник данных также предоставляется контейнером


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

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

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


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

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

A транзакция-это единица работы (теоретически тоже сессия). Он привязан к базовой системе транзакций РСУБД и привязан к сеансу, на котором он был открыт.

в контексте "container managed entity manager" (то, что вы называете CMT) контейнер будет отвечать за привязку вашего сеанса к определенной области и распространение транзакций в соответствии с обнаруженным @Transactional аннотация по вызову методов.

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

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

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

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

см. Luk anwser ниже

к вашему сведению Транзакции, Управляемые Контейнером

редактировать (согласно изданию вопроса)

посмотреть разница между источником данных" jta-datasource "и источником данных " resource-local"?

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

из спецификации EJB 3.0, раздел 13.3.4 Enterprise Beans с использованием демаркации транзакций, управляемых контейнером:

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

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

sessionFactory.getCurrentSession() 

но вы не должны использовать TX = session.beginTransaction (), но вместо

@TransactionAttribute(TransactionAttributeType.REQUIRED) 

см. раздел демаркации транзакций с разделом EJB / CMT в документе JBoss выше