Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate - CMT EJB using programmatic transaction idiom

What happens when the following programmatic transaction and session idiom is used with within CMT (EJB3) and Hibernate Core is set up to use CMT?
Assumed a current CMT transaction is required and started using default @TransactionAttribute(REQUIRED)

  1. Will the hibernate transaction join the current CMT on beginTransaction()?
  2. Will commit() try to commit the hibernate transaction immediately or wait until the current CMT commits?
  3. What happens when closing the session in CMT?

B. Does the behavior depends if the current-session is bound to CMT using 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();
}

In my application currently i am using a single database and it worked fine using programmatic JDBC transactions with Hibernate. Now the application also uses a JMS-Queue for Mail messaging and would like to merge it into the global CMT transaction.

Edit:

At the moment i am not using EntityManager in the application at all and also would like to keep code portable to non-managed environments.

Hibernate configuration hibernate.cfg.xml to enable CMT:

Hibernate 4.2.6 and 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 retrieval

SessionFactory is build within an singleton EJB. Stripped unnecessary stuff.

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

    public SessionManager()
    {
        final Configuration configuration = new Configuration().configure();
        this.sessionFactory = configuration.buildSessionFactory();
    }
}
like image 214
djmj Avatar asked Jan 15 '14 01:01

djmj


People also ask

What is the use of @transactional in Hibernate?

The @Transactional annotation is the metadata that specifies the semantics of the transactions on a method. We have two ways to rollback a transaction: declarative and programmatic. In the declarative approach, we annotate the methods with the @Transactional annotation.

What is Hibernate entity transaction?

Interface EntityTransactionInterface used to control transactions on resource-local entity managers. The EntityManager. getTransaction() method returns the EntityTransaction interface. Since: Java Persistence 1.0.

What is Java CMT?

In JavaEE environments Hibernate can use the CMT (Container Managed Transaction) strategy which will bind hibernate transactions with the underlying JTA transaction eliminating the need to manually begin, commit and rollback transactions.

Which of the following method is used to start a transaction in programmatic transaction management in Hibernate?

Once the TransactionDefinition is created, you can start your transaction by calling getTransaction() method, which returns an instance of TransactionStatus.


2 Answers

As Luk has pointed out, this is not the way to code it in CMT enviroment. Anyway, the session.beginTransaction() part is safe here according to http://docs.jboss.org/hibernate/annotations/3.5/api/org/hibernate/Session.html#beginTransaction%28%29 which says

If a new underlying transaction is required, begin the transaction. Otherwise continue the new work in the context of the existing underlying transaction

tx.rollback() is also safe. It's not stated in the doc, but a CMTTransaction actually executes getTransaction().setRollbackOnly(), i.e. it simply marks the TX for rollback. The commit actually does not commit the TX, but may flush the session. A real commit would violate the transaction semantics if more than one resource is involved.

like image 116
Drunix Avatar answered Oct 20 '22 12:10

Drunix


With CMT (Container Managed Transaction) you don't declare anything like tx = session.beginTransaction(); you let the container do the work for you. You would only specify when and if the container supports transactions. Check out the oracle doc Java EE 5 Tutorial

Lets say you have an EJB, its default transaction scope is Required. So hibernate will actually be bound to that transaction scope.

following example with first ejb with no transaction which calls another one with a 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");
    }
}

when the methode doSomething() is done, the container will flush and commit the update to the databese since the outer ejb doesn't have a running transaction. This only works if the datasource is also provided by the container

like image 1
Luk Avatar answered Oct 20 '22 13:10

Luk