0

I try to describe my environment shortly. Technologies: EJB 3.1, JSF, JBoss 7.1.1

There are Servise-classes (@SessionScoped @Stateful). Servise-classes call Dao classes (@Stateless)

I want :

  • use EntityManager only into @StateLess beans (Dao)
  • have short transaction in most cases (like persist, merge)
  • have one long transaction for some multistep-methods (methods are in Dao also)
  • have actual (up to date, without first-level cache) data

I have: Pesistense.xml

    <provider>org.hibernate.ejb.HibernatePersistence</provider>

    <jta-data-source>java:jboss/datasources/MydataSource</jta-data-source>
    <properties>

        <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
        <property name="hibernate.dialect"value="org.hibernate.dialect.PostgreSQLDialect"/>
        <property name="hibernate.transaction.manager_lookup_class"
                  value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
        <property name="hibernate.connection.autocommit" value="true"/>
        <property name="hibernate.connection.characterEncoding" value="utf8"/>

        <property name="hibernate.c3p0.min_size" value="5"/>
        <property name="hibernate.c3p0.max_size" value="20"/>
        <property name="hibernate.c3p0.timeout" value="1800"/>
        <property name="hibernate.c3p0.max_statements" value="50"/>

    </properties>

</persistence-unit>

Dao

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class UserDaoBean implements UserDAO, Serializable {

    @PersistenceContext(name = "MyEntityManager")
    private EntityManager em;

     @Override
     @Transactional
 public void update(User user) throws Exception {
        User tmpUser = getUser(user.getUser());
       //some code, should be rollback, if it is an exception
        em.persist(tmpUser);

    }

Transaction interceptor

@Transactional
@Interceptor
public class TransactionInterceptor implements Serializable {


    @Resource
    private UserTransaction userTransaction;

    @AroundInvoke
    public Object verifyAccess(InvocationContext context) throws
            Exception {
        Object result = null;

        try {
            userTransaction.begin();
            result = context.proceed();
            userTransaction.commit();
        } catch (Exception e) {
                userTransaction.rollback();
             throw new CustomRuntimeException(e.getMessage());
        }

        return result;
    }

}

Problem: If it is throw an Exception into Dao method, part data will save in DB instead of total rollback.

I think, is need Join Transaction to EM. Or disconnect persists each item to the DB right away (using cache). I've try different ways, but didn't have success.

Thanks for in advance!

Olga
  • 3,705
  • 1
  • 20
  • 23

1 Answers1

0

This like looks particularly problematic:

<property name="hibernate.connection.autocommit" value="true"/>

You shouldn't be doing any connection management at all in your persistence.xml file. The <jta-data-source> element and the notion of putting connection information in <properties> are mutually exclusive.

Either the JPA provider creates and manages connections (using properties) or it gets the connections from the container (using jta-data-source). Putting both in there will give you unpredictable results. If the JPA provider chooses to honor the connection properties you can quite easily shut off transaction management, connection pooling and more.

What you want is to configure all those things in the container and do not do any of that in the persistence unit declaration.

UPDATE

The combination of TransactionManagementType.BEAN (BMT) and UserTransaction should be fine. Note that you'll want to catch Throwable rather than Exception. As well the rollback() call can also throw exceptions which should be handled. Overall, though, this should produce the results you want.

Note carefully that while this looks to be nearly identical to what you get from TransactionManagementType.CONTAINER (CMT) and no interceptor, they do differ in one critical way:

  • Two CMT beans can share the same transaction
  • Two BMT beans can not share the same transaction.

This is because the container is required to suspend any transaction that might be in progress before invoking any bean using BMT. In that regard the term Bean-Managed Transaction is actually a bit of a misnomer as the container will always take action on any transactions in progress before invoking the BMT bean.

As such BMT and CMT are not on equal footing and it is actually impossible to implement some of the basic CMT features such as SUPPORTS or REQUIRED using BMT.

David Blevins
  • 19,178
  • 3
  • 53
  • 68
  • Thanks for replay! I've remove all properties from persistence.xml (except of ) – Olga Jun 20 '12 at 12:44
  • Thanks for replay! I think, it is a good observation. But it didn't resolve my problem. May problem is related to TransactionManagementType (it should use TransactionManagementType.CONTAINER, but in this case I got exception: "java.lang.IllegalStateException: Wrong tx on thread: expected TransactionImple" ) – Olga Jun 20 '12 at 12:55