JTA UserTransaction回滚不起作用

时间:2012-06-15 10:20:51

标签: jpa ejb translation jta

我试着尽快描述我的环境。技术:EJB 3.1,JSF,JBoss 7.1.1

有Servise-classes(@SessionScoped @Stateful)。 Servise-classes调用Dao类(@Stateless)

我想:

  • 仅将EntityManager用于@StateLess bean(Dao)
  • 在大多数情况下都有简短的交易(比如坚持,合并)
  • 对于某些多步骤方法有一个长事务(方法也在Dao中)
  • 拥有实际(最新,没有第一级缓存)数据

我有: 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>

@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);

    }

交易拦截器

@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;
    }

}

问题: 如果它向Dao方法抛出异常,则部分数据将保存在DB中而不是全部回滚。

我认为,需要将交易加入EM。或者断开连接将每个项目立即保存到数据库(使用缓存)。  我尝试了不同的方法,但没有成功。

提前感谢!

1 个答案:

答案 0 :(得分:0)

这看起来特别有问题:

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

您不应该在persistence.xml文件中进行任何连接管理。 <jta-data-source>元素以及在<properties>中放置连接信息的概念是互斥的。

JPA提供程序创建和管理连接(使用属性),或者从容器获取连接(使用jta-data-source)。将两者放在那里会给你带来不可预测的结果。如果JPA提供程序选择遵守连接属性,则可以非常轻松地关闭事务管理,连接池等。

您想要的是在容器中配置所有这些内容,而不是在持久性单元声明中执行任何操作。

更新

TransactionManagementType.BEAN(BMT)和UserTransaction的组合应该没问题。请注意,您需要抓住Throwable而不是Exception。同样,rollback()调用也可以抛出应该处理的异常。但总的来说,这应该产生你想要的结果。

请注意,尽管这看起来几乎与您从TransactionManagementType.CONTAINER(CMT)获得的内容完全相同,并且没有拦截器,但它们在一个关键方面确实存在差异:

  • 两个CMT bean可以共享同一个事务
  • 两个BMT bean可以共享同一个交易。

这是因为在使用BMT调用任何bean之前,容器需要挂起可能正在进行的任何事务。在这方面,术语 Bean-Managed Transaction 实际上有点用词不当,因为容器总是在调用BMT bean之前对正在进行的任何事务采取行动。

因此BMT和CMT不是平等的,实际上不可能使用BMT实现一些基本的CMT功能,例如SUPPORTSREQUIRED