Hibernate-CMT EJB с использованием идиомы программной транзакции
что происходит, когда следующая программная транзакция и идиома сеанса используются в CMT (EJB3), а Hibernate Core настроен на использование CMT?
предполагается, что текущая транзакция CMT требуется и запускается с использованием default @TransactionAttribute(REQUIRED)
- будет ли транзакция hibernate присоединяться к текущему CMT на
beginTransaction()
? - будет
commit()
попробуйте немедленно зафиксировать транзакцию спящего режима или дождитесь текущего CMT совершает? - что происходит при закрытии сессии в 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 выше