1、在action中获取UserTransaction,并调用UserTransaction.begin()方法;
2、调用sessionbean1和sessionbean2的方法;
3、调用UserTransaction.commit/rollback完成事务。

解决方案 »

  1.   


    问题一:
    在action中通过手动获取UserTransaction,sessionbean1和sessionbean2事务管理方式为BMT对吗?问题二:
    如果通过spring将UserTransaction注入到action中,配置文件如何写?问题三:
    如果我不想通过UserTransaction手动控制事务的边界,即我想用CMT,又该如何做?谢谢
      

  2.   

    问题一:
    在action中通过手动获取UserTransaction,sessionbean1和sessionbean2事务管理方式为BMT对吗?BMT和CMT基本都是针对service/ejb而言的,事务管理一般也都在Service层/ejb上控制,Action/jsp/servlet等前段程序无所谓BMT/CMT,如果需要跨多个service/ejb,就需要使用UserTransaction。此时,被调用的ejb(如你所说sessionbean1/sessionbean2)/service仍然属于CMT。问题二:
    如果通过spring将UserTransaction注入到action中,配置文件如何写? <bean id="transactionManager" class="...TransactionManagerImpl" />
    <bean id="userTransaction" class="...UserTransactionImpl" />
    <bean id="jtaTransactionManager"
    class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="userTransaction" ref="userTransaction" />
    <property name="transactionManager" ref="transactionManager" />
    </bean>
    <tx:annotation-driven transaction-manager="jtaTransactionManager" />类似如上这样,然后通过ApplicationContext.getBean("userTransaction")获取即可。问题三:
    如果我不想通过UserTransaction手动控制事务的边界,即我想用CMT,又该如何做?如果你的操作在ejb/service里的话,是可以的。直接标注一下事务属性为Required,容器就帮你管理事务了。但看你的描述你的操作在Action中,Action里容器是无法管理事务的,如果你希望事务跨两个service/ejb,可以尝试:1)通过UserTransaction;2)将跨两个service/ejb的操作提取出来,放在一个新的ejb/service中。
      

  3.   


    首先非常感谢您的帮助,谢谢您耐心的回答在问题二中:
    <bean id="transactionManager" class="...TransactionManagerImpl" />
    <bean id="userTransaction" class="...UserTransactionImpl" />TransactionManagerImpl和UserTransactionImpl这两个实现类是自己写得吗?
    <tx:annotation-driven transaction-manager="jtaTransactionManager" />这句话起什么作用?
    为什么不用指定数据源?
    在问题三中:
    “将跨两个service/ejb的操作提取出来,放在一个新的ejb/service中”首先看一下结构图:我无法将在不同机器上的多个session bean注入到本地的session bean中(在图中,session bean3和session bean 4注入到sessionbean1中),该怎么处理能顺利注入?另外,这种情况下,肯定会涉及到分布式事务,我使用的是<datasources>
      <xa-datasource>类型的数据源,在不同机器上分别放置了oracle-xa-ds.xml,但事务并不起作用。
    我想知道,这几台服务器上的数据源文件是不是应该一模一样?具体怎么配置?再把我的oracle-xa-ds.xml附上:
    <?xml version="1.0" encoding="UTF-8"?>
    <datasources>
      <xa-datasource>
        <jndi-name>MyOracleDS</jndi-name>
        <isSameRM-override-value>false</isSameRM-override-value>
        <xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>

          <!--服务器249 -->
        <xa-datasource-property name="URL">jdbc:oracle:thin:@192.168.24.249:1521:ORCL</xa-datasource-property>
        <xa-datasource-property name="User">gxpt1</xa-datasource-property>
        <xa-datasource-property name="Password">gxpt1</xa-datasource-property>
        <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name>
        <no-tx-separate-pools/>
          <metadata>
             <type-mapping>Oracle9i</type-mapping>
          </metadata>
      </xa-datasource>
      
      <xa-datasource>
        <jndi-name>JcOracleDS</jndi-name>
        <isSameRM-override-value>false</isSameRM-override-value>
     <!--服务器252 -->
        <xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
        <xa-datasource-property name="URL">jdbc:oracle:thin:@192.168.24.252:1521:ORCL</xa-datasource-property>
        <xa-datasource-property name="User">gxpt1</xa-datasource-property>
        <xa-datasource-property name="Password">gxpt1</xa-datasource-property>    <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name>
        <no-tx-separate-pools/>
          <metadata>
             <type-mapping>Oracle9i</type-mapping>
          </metadata>
      </xa-datasource>  
      <mbean code="org.jboss.resource.adapter.jdbc.vendor.OracleXAExceptionFormatter" 
             name="jboss.jca:service=OracleXAExceptionFormatter">
        <depends optional-attribute-name="TransactionManagerService">jboss:service=TransactionManager</depends>
      </mbean></datasources>
      

  4.   

    说实话,我非常好奇你们的系统框架,怎么又是spring又是ejb的呢?
    首先非常感谢您的帮助,谢谢您耐心的回答在问题二中:
    <bean id="transactionManager" class="...TransactionManagerImpl" />
    <bean id="userTransaction" class="...UserTransactionImpl" />TransactionManagerImpl和UserTransactionImpl这两个实现类是自己写得吗?
    这个是事务管理器,如果在spring里使用分布式事务管理器需要自行指定,不过不一定要自己写,网上有不少开源的jta实现,如jotm。(本人刚新开了一个openjta的项目,如果有兴趣可以关注一下,哈哈http://code.google.com/p/openjta),不过如果你用jboss的话,就完全就不必使用spring来管理事务了。如果要获取UserTransaction的话直接通过jndi来lookup就行。。<tx:annotation-driven transaction-manager="jtaTransactionManager" />这句话起什么作用?
    这个配置告诉spring容器根据注解的事务属性来控制事务,并告知spring容器事务管理器。为什么不用指定数据源?
    可能你之前使用DataSourceTransactionManager比较多,所以觉得需要指定数据源。一般来说,事务管理器没法指定数据源,因为参与事务的数据源可能会有0~n个(DataSourceTransactionManager只支持一个数据源所以才可以指定)。如果在spring用JtaTransactionManager的话,一般是在数据源中指定事务管理器。
    在问题三中:
    “将跨两个service/ejb的操作提取出来,放在一个新的ejb/service中”首先看一下结构图:我无法将在不同机器上的多个session bean注入到本地的session bean中(在图中,session bean3和session bean 4注入到sessionbean1中),该怎么处理能顺利注入?远程Ejb一般只能通过lookup获得吧我之前的意思是你可以将服务器c中的sessionbean1和sessionbean2组合到一个新的sessionbean0中(sessionbean0仍然部署在服务器c中,sessionbean0的操作与你现在在action中的操作相同) ,然后你在action中调用sessionbean0,这样action就只调用一个sessionbean了。另外,这种情况下,肯定会涉及到分布式事务,我使用的是<datasources>
      <xa-datasource>类型的数据源,在不同机器上分别放置了oracle-xa-ds.xml,但事务并不起作用。
    我想知道,这几台服务器上的数据源文件是不是应该一模一样?具体怎么配置?再把我的oracle-xa-ds.xml附上:
    <?xml version="1.0" encoding="UTF-8"?>
    <datasources>
      <xa-datasource>
        <jndi-name>MyOracleDS</jndi-name>
        <isSameRM-override-value>false</isSameRM-override-value>
        <xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>

          <!--服务器249 -->
        <xa-datasource-property name="URL">jdbc:oracle:thin:@192.168.24.249:1521:ORCL</xa-datasource-property>
        <xa-datasource-property name="User">gxpt1</xa-datasource-property>
        <xa-datasource-property name="Password">gxpt1</xa-datasource-property>
        <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name>
        <no-tx-separate-pools/>
          <metadata>
             <type-mapping>Oracle9i</type-mapping>
          </metadata>
      </xa-datasource>
      
      <xa-datasource>
        <jndi-name>JcOracleDS</jndi-name>
        <isSameRM-override-value>false</isSameRM-override-value>
     <!--服务器252 -->
        <xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
        <xa-datasource-property name="URL">jdbc:oracle:thin:@192.168.24.252:1521:ORCL</xa-datasource-property>
        <xa-datasource-property name="User">gxpt1</xa-datasource-property>
        <xa-datasource-property name="Password">gxpt1</xa-datasource-property>    <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name>
        <no-tx-separate-pools/>
          <metadata>
             <type-mapping>Oracle9i</type-mapping>
          </metadata>
      </xa-datasource>  
      <mbean code="org.jboss.resource.adapter.jdbc.vendor.OracleXAExceptionFormatter" 
             name="jboss.jca:service=OracleXAExceptionFormatter">
        <depends optional-attribute-name="TransactionManagerService">jboss:service=TransactionManager</depends>
      </mbean></datasources>
    jboss服务器我用的不多,这么具体配置,我也看不出啥问题来
      

  5.   


    架构方面大致是这样的---
    web客户端用得是:spring+struts底层业务逻辑用得是:ejb通过spring,将远程ejb sessionbean注入struts控制的action中。------用到现在,我也感觉有些不伦不类了,不知道我表达得是否清晰。
    我按照你说的方式,做了如下demo--
    我在一个ejb sessionbean(A)中,需要注入远程的session bean(B)和远程的session bean(C),代码如下:
    @Stateless
    @Remote( ISessionBeanA.class)
    @TransactionManagement(TransactionManagementType.CONTAINER)
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public class SessionBeanA implements ISessionBeanA {
        
    @Resource(mappedName = "SessionBeanB/Remote")
    private ISessionBeanB sessionBeanB;
    @Resource(mappedName = "SessionBeanC/Remote")
    private ISessionBeanC  sessionBeanC;        @Override
    public void addOrder(Order order) {
    sessionBeanB.save(order.getBasicinfo());
                    sessionBeanC.save(order.getClient());
    }
    如上代码,我该如何注入sessionBeanB和sessionBeanC?
    我试过加入jndi文件:
    java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
    java.naming.provider.url=192.168.24.249,192.168.24.252sessionBeanB在192.168.24.249上部署着,sessionBeanC在192.168.24.252上部署着。按上述配置,sessionBeanB注入成功,sessionBeanC输入失败。
    如果将jndi中java.naming.provider.url=192.168.24.249,192.168.24.252改为
    java.naming.provider.url=192.168.24.252,192.168.24.249,则sessionBeanC注入成功,sessionBeanB注入失败。如果sessionBeanA,sessionBeanB和sessionBeanC在一个服务器上,那么能注入成功,没有问题,但现在条件不允许我将他们拿到一个机器上来。谢谢您耐心为解答。
      

  6.   

    我上面的回复中应该已经提到过:远程服务器实例上的EJB貌似只能通过lookup获取吧。你确定注入别的服务器上的EJB是可行的么?