假设对象 A 的 methodA() 启动一个事务,然后调用对象 B 的 methodB()(对象 B 将得到一个 JDBC 连接并更新数据库)。B 获得的连接将被自动征调到 A 创建的事务中。容器怎么知道要做这件事?当事务启动时,事务上下文与执行线程关联在一起。当 A 创建事务时,A 在其中执行的线程与该事务关联在一起。由于本地方法调用与主调程序(caller)在同一个线程内执行,所以 A 调用的每个方法也都在该事务的上下文中。如果对象 B 其实是在另一个线程,甚至另一个 JVM 中执行的 EJB 组件的存根,情况会怎样?远程对象 B 访问的资源仍将在当前事务中被征用。EJB 对象存根(在主调程序的上下文中执行的那部分)、EJB 协议(IIOP 上的 RMI)和远端的骨架对象协力要使其透明地发生。存根确定调用者是不是正在执行一个事务。如果是,事务标识,或者说 Xid,被作为 IIOP 调用的一部分与方法参数一起传播到远程对象。(IIOP 是 CORBA 远程-调用协议,它为传播执行上下文(比如事务上下文和安全性上下文)的各种元素而备;关于 RMI over IIOP 的更多信息,请参阅参考资料。)如果调用是事务的一部分,那么远程系统上的骨架对象自动设置远程线程的事务上下文,这样,当调用实际的远程方法时,它已经是事务的一部分了。(存根和骨架对象还负责开始和提交容器管理的事务。) 事务可以由任何 J2EE 组件来启动 — 一个 EJB 组件、一个 servlet 或者一个 JSP 页面(如果容器支持的话,还可以是一个应用程序客户机)。这意味着,应用程序可以在请求到达时在 servlet 或者 JSP 页面中启动事务、在 servlet 或者 JSP 页面中执行一些处理、作为页面逻辑的一部分访问多个服务器上的实体 bean 和会话 bean 并使所有这些工作透明地成为一个事务的一部分。

解决方案 »

  1.   

    回复hutlyx(胡里糊涂) :也就是说transacton context是被RMI/IIOP机制,具体地说就是stub/skeleton透明地处理的,在J2EE应用服务器中,只要将thread与transaction作出bind就可以了,RMI/IIOP do the everything else, right?
      

  2.   

    事务的上下文以及事务的传播对于应用程序来说是完全透明的,线程具体怎样与一个事务context联系起来,不同事务管理器的实现可以有不同的实现。使用JTA来调用application Server的事务服务,这样通过UserTransaction的begin()方法开始一个全局事务,底层的执行过程是,应用服务器将请求转发给Transaction Manager,通过调用TransactionManger的begin()方法产生一个全局事务,也就是创建了一个实现了Transaction接口的对象.Transaction会在创建Transaction对象时生成一个Xid对象作为全局Transaction的标示,Xid可以是一个随机数,也可以是一个累增的序列号,只要保证唯一就可以。最后,TransactionManager还要做的一件事情就是将这个产生的Transaction与请求线程进行绑定。根据JDBC规范的描述,DataSource必须由应用服务器实现,客户端通过JNDI获得。大部分应用服务器明确的将DataSource分为一般的DataSource和XADataSource,而且,只有XADataSource才能加入全局事务(分布式事务)。这是应为,客户端通过JNDi获得DataSource的过程中,为了进行分布式事务处理,用服务器作了很多的工作。
      

  3.   

    OK, thanks.大家有空研究一下,:)
      

  4.   

    [转]说穿了就不会觉得神奇了( 有点像变魔术:-) ),这是由JTA服务器内部实现的,我可以说一下大致的原理(远程事务的部分就不说了(说来话长))。
    当调用begin时,创建一个新事务,并将其放入事务池(是一个Map对象)中,其键值就是线程对象。大概是这样的:TransactionManager.getTranactionPool().put(System.currentThread(),new TransactionObject());
    当事务资源如会话Bean需要用到当前事务对象时,就调用
    TransactionManager.getTranactionPool().get(System.currentThread());来获得。这也就是为什么EJB容器规定不能在容器中启动新线程的原因之一了(因为容器不好控制(也不是不可能)事务在新线程中传播)。
      

  5.   

    [转]
    在JBoss里,你提到的应用是这样实现的:
    首先,你要明确:你用到到的那几个bean位于同一个容器中(跨容器的事务传播JBoss3.x不支持,JBoss4.x我不懂),那么这几个bean的调用将位于同一个线程中。
    而事务管理器TxManager使用了ThreadLocal类型的变量来保存特定线程的事务信息(包括事务对象),这样那几个位于同一线程的调用就共有了同一个事务对象,也就是说被纳入到同一个事务了。就着么简单!因为在取得资源时判断当前是否有事务的方式,就是判断TxManager中的ThreadLocal变量是否保存了事务对象。
    而对于客户端调用EJB方法时的事务传播,因为事务对象其实是存在于容器中的,所以客户端只需在调用EJB方法时顺带捎上事务的全局ID,容器根据改ID取出相应的事务对象,就将客户端和EJB方法纳入到同一个事务中了。这其实是一种变形的跨JVM传播事务,但不是真正的跨JVM传播事务。