【问题标题】:Spring + RMI + transactions + weblogicSpring + RMI + 事务 + weblogic
【发布时间】:2014-08-21 10:27:12
【问题描述】:

我们使用 Spring 3、Hibernate 4 和 JPA 开发了两个 Web 服务(A、B)。

在服务A的方法内部,我们需要调用服务B的方法。访问是通过RMI。 问题是他们两个需要在同一个事务中。我认为我们遵循了所有处理事务的规则,但是当服务 B 中的方法被调用后服务 A 崩溃时,我们不能回滚服务 B 中的方法。

如果在调用服务B后在服务A中抛出exception,则服务A更改的数据回滚,而不是服务B更改的数据。看来事务是在服务 B 中更新,而不包括在服务 B 中创建的服务中。

我们使用在weblogic 中创建的jndi 数据源。 事务方法注释为:

*@Transactional( readOnly = false, isolation=Isolation.SERIALIZABLE, 
                rollbackFor=Exception.class, propagation = Propagation.REQUIRED )*

这是我处理事务的配置:

spring-server.xml(服务与服务之间唯一不同的数据是持久化单元名称):

    *<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
         <property name="persistenceUnitName" value="SAPOY/SANOT" />
         </bean>
    <bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="allowCustomIsolationLevels" value="true"/>
        <property name="globalRollbackOnParticipationFailure" value="true" />
    </bean>
    <tx:annotation-driven transaction-manager="jtaTransactionManager" proxy-target-class="true" />
<!-- Servicio SAPOY.SANOT -->
    <bean id="sanot" class="com.sems.sapoy.sanot.services.impl.Sanot">
        <property name="sanotBiz" ref="sanotBiz" />
   </bean>*

persistence.xml(服务与服务之间唯一不同的数据是持久化单元名称):

*<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
                        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="SAPOY/SANOT" transaction-type="JTA">
        <description>Unidad de Persistencia del modulo SANOT</description>
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>jdbc/xaDS</jta-data-source>


        <properties>
            <!-- 
            ################################################################
            HIBERNATE
            ################################################################ 
            -->
            <property name="hibernate.archive.autodetection" value="class" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.query.factory_class"
                      value="org.hibernate.hql.classic.ClassicQueryTranslatorFactory" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
            <property name="hibernate.autoReconnect" value="true" />
            <property name="hibernate.autoReconnectForPools" value="true" />
            <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.WeblogicTransactionManagerLookup" />
            <property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory" />

            <!-- 
            ################################################################
            CONNECTION
            ################################################################ 
            -->
            <property name="hibernate.connection.autocommit" value="false"/>
            <!-- 
            ################################################################
            CACHE
            ################################################################ 
            -->
            <property name="hibernate.cache.use_second_level_cache" value="true" />
            <property name="hibernate.cache.region.factory_class" value="net.sf.ehcache.hibernate.EhCacheRegionFactory" />
            <property name="hibernate.cache.use_query_cache" value="true" />
        </properties>
    </persistence-unit>
</persistence>*

【问题讨论】:

  • 您是否尝试过使用自定义 WebLogicJtaTransactionManager 而不是普通的 JtaTransactionManager 以及如何调用 RMI 您是使用 Spring 的 RMI Remoting 还是您自己的 RMI 生成的存根?另请参阅this forum post
  • 我尝试使用 WebLogicJtaTransactionManager 但得到了相同的结果。

标签: spring hibernate transactions weblogic


【解决方案1】:

您的 DataSource/TransactionManager 配置很好,唯一的问题是您通过 RMI 调用了其他服务。

全局事务必须从可能征用一个或多个资源(JDBC 连接/JMS 队列)的同一运行线程协调,但不能跨越多个线程。

当您调用 RMI 方法时,该调用将由 RMI 服务器提供服务,该服务器分配一个工作线程来服务您的 RMI 请求。即使该方法是@Transactional,事务也会在 RMI 工作线程边界定义。

尝试删除 RMI 调用,它会起作用。在多台服务器上实现它并不是一件容易的事。您可能必须使用Command pattern 之类的东西,以便服务A 可以在服务A 未能提交时调用服务B 撤消。就像我说的,这不像全局 XA 事务那么简单。它需要仔细设计,并且可能会导致在其他事务已经使用已提交的更改之后发生由于撤消而发生的不一致。

为此,您需要 WS-TransactionsApplication server to support it。 JTA 本身以线程为基础管理全局事务。要跨多个线程跨越事务,您需要更高级别的协议,例如 WS-Transactions。

【讨论】:

  • 我明白你的解释,但如果我不能加入两个不同的服务调用,什么是分布式事务?
  • 在一个全局事务中,你可以加入两个不同的服务调用,只要它们是从同一个线程发出的。
  • 我不明白最后的评论,如何从同一个线程调用不同的 Web 服务?
  • 为此,您需要WS-TransactionsApplication server to support it。 JTA 本身以线程为基础管理全局事务。要跨多个线程跨越事务,您需要更高级别的协议,例如 WS-Transactions。
猜你喜欢
  • 1970-01-01
  • 2013-10-08
  • 1970-01-01
  • 1970-01-01
  • 2011-03-10
  • 1970-01-01
  • 2012-06-15
  • 1970-01-01
  • 2018-01-01
相关资源
最近更新 更多