Spring JtaTransactionManager不会将资源与外部JTA事务同步

时间:2015-07-27 21:09:20

标签: spring jpa jta

我正在使用带弹簧的eclipselink。我有一些JPA实体和DAO实现为spring bean。对于事务管理,我使用的是JtaTransactionManager。这是我的春季配置:

<beans>
    <context:annotation-config />

    <context:component-scan base-package="daopackage" />

    <tx:annotation-driven proxy-target-class="true" />

    <tx:jta-transaction-manager />

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="loadTimeWeaver">
            <bean class="org.springframework.instrument.classloading.jboss.JBossLoadTimeWeaver"/>
        </property>
    </bean>
</beans>

另外,我显然有persistence.xml,但是我会跳过它,没有什么不寻常的,而且持久性本身也很好。

问题在于:在我看来,即使在使用JtaTransactionManager的情况下,Spring仅将所有事务资源与其内部事务上下文同步,并且不会将其绑定到JTA事务上下文。 DAO代码:

class Dao {
    @PersistenceContext
    protected EntityManager manager;

    @Transactional(propagation = MANDATORY)
    public JpaEntity getById(BigInteger id) {
        return manager.find(JpaEntity.class, id);
    }

    @Transactional(propagation = MANDATORY)
    public void remove(JpaEntity entity) {
        manager.remove(entity)
    }
}

测试代码:

UserTransaction transaction = getTransaction(); // lookup by jndi name
transaction.begin();
Dao dao = getDao(); // obtain from ApplicationContext
JpaEntity entity = dao.getById(id);
dao.remove(entity);
transaction.commit();

注入bean的EntityManager是共享实体管理器代理,它应该从绑定到当前事务的线程本地持有者获得实体管理器实现。至于当前事务是由JTA创建的,getById()和remove()的调用应该使用相同的实体管理器实现,其缓存一直存在直到commit()调用。但是,此代码在remove()调用期间产生错误 - 实体管理器认为实体已分离。

调试显示共享实体管理器代理对getById()和remove()调用使用不同的实体管理器。我已经启动了Spring代码调试并发现Spring事务拦截器在调用截获的方法后实际执行内部提交操作,包括解除所有线程本地资源(实体管理器所在的位置)和调用事务同步侦听器(在这种情况下 - 关闭实体管理器) )。注意,传播属性是MANDATORY,并且在拦截器调用之前,事务是在外部启动的。对我来说似乎很自然,在JTA事务提交之前,不应该处理线程本地资源并且不会调用侦听器。

有人可以帮我找到使其正常工作的方法吗?

0 个答案:

没有答案