`
king1065
  • 浏览: 4133 次
  • 性别: Icon_minigender_1
  • 来自: 哈尔滨
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论
阅读更多
Java 理论和实践: 理解 JTS什么是 JTS?   JTS 是一个 组件事务监视器(component transaction monitor)。这是什么意思?我们将介绍事务处理监视器(TPM)这个概念,TPM 是一个程序,它代表应用程序协调分布式事务的执行。TPM 与数据库出现的时间长短差不多;在 60 年代后期,IBM 首先开发了 CICS,至今人们仍在使用。经典的(或者说 程序化)TPM 管理被程序化定义为针对事务性资源(比如数据库)的操作序列的事务。随着分布式对象协议,如 CORBA、DCOM 和 RMI 的出现,人们希望看到事务更面向对象的前景。将事务性语义告知面向对象的组件要求对 TPM 模型进行扩展 ― 在这个模型中事务是按照事务性对象的调用方法定义的。JTS 只是一个组件事务监视器(有时也称为 对象事务监视器(object transaction monitor)),或称为 CTM。

  JTS 和 J2EE 的事务支持设计受 CORBA 对象事务服务(CORBA Object Transaction Service,OTS)的影响很大。实际上,JTS 实现 OTS 并充当 Java 事务 API(Java Transaction API)― 一种用来定义事务边界的低级 API ― 和 OTS 之间的接口。使用 OTS 代替创建一个新对象事务协议遵循了现有标准,并使 J2EE 和 CORBA 能够互相兼容。

  乍一看,从程序化事务监视器到 CTM 的转变好像只是术语名称改变了一下。然而,差别不止这一点。当 CTM 中的事务提交或回滚时,与事务相关的对象所做的全部更改都一起被提交或取消。但 CTM 怎么知道对象在事务期间做了什么事?象 EJB 组件之类的事务性组件并没有 commit() 或 rollback() 方法,它们也没向事务监视器注册自己做了什么事。那么 J2EE 组件执行的操作如何变成事务的一部分呢?

  透明的资源征用

  当应用程序状态被组件操纵时,它仍然存储在事务性资源管理器(例如,数据库和消息队列服务器)中,这些事务性资源管理器可以注册为分布式事务中的资源管理器。在第 1 部分中,我们讨论了如何在单个事务中征用多个资源管理器,事务管理器如何协调这些资源管理器。资源管理器知道如何把应用程序状态中的变化与特定的事务关联起来。

  但这只是把问题的焦点从组件转移到了资源管理器 ― 容器如何断定什么资源与该事务有关,可以供它征用?请考虑下面的代码,在典型的 EJB 会话 bean 中您可能会发现这样的代码:

  清单 1. bean 管理的事务的透明资源征用

1 InitialContext ic = new InitialContext();
2   UserTransaction ut = ejbContext.getUserTransaction();
3   ut.begin();
4   DataSource db1 = (DataSource) ic.lookup("java:comp/env/OrdersDB");
5   DataSource db2 = (DataSource) ic.lookup("java:comp/env/InventoryDB");
6   Connection con1 = db1.getConnection();
7   Connection con2 = db2.getConnection();
8   // perform updates to OrdersDB using connection con1
9   // perform updates to InventoryDB using connection con2
10   ut.commit();
11
  注意,这个示例中没有征用当前事务中 JDBC 连接的代码 ― 容器会为我们完成这个任务。我们来看一下它是如何发生的。

  资源管理器的三种类型

  当一个 EJB 组件想访问数据库、消息队列服务器或者其它一些事务性资源时,它需要到资源管理器的连接(通常是使用 JNDI)。而且,J2EE 规范只认可三种类型的事务性资源 ― JDBC 数据库、JMS 消息队列服务器和“其它通过 JCA 访问的事务性服务”。后面一种服务(比如 ERP 系统)必须通过 JCA(J2EE Connector Architecture,J2EE 连接器体系结构)访问。对于这些类型资源中的每一种,容器或提供者都会帮我们把资源征调到事务中。

  在清单 1 中, con1 和 con2 好象是普通的 JDBC 连接,比如那些从 DriverManager.getConnection() 返回的连接。我们从一个 JDBC DataSource 得到这些连接,JDBC DataSource 可以通过查找 JNDI 中的数据源名称得到。EJB 组件中被用来查找数据源( java:comp/env/OrdersDB )的名称是特定于组件的;组件的部署描述符的 resource-ref 部分将其映射为容器管理的一些应用程序级 DataSource 的 JNDI 名称。

  隐藏的 JDBC 驱动器

  每个 J2EE 容器都可以创建有事务意识的池态 DataSource 对象,但 J2EE 规范并不向您展示如何创建,因为这不在 J2EE 规范内。浏览 J2EE 文档时,您找不到任何关于如何创建 JDBC 数据源的内容。相反,您不得不为您的容器查阅该文档。创建一个数据源可能需要向属性或配置文件添加一个数据源定义,或者也可以通过 GUI 管理工具完成,这取决于您的容器。

  每个容器(或连接池管理器,如 PoolMan)都提供它自己的创建 DataSource 机制,JTA 魔术就隐藏在这个机制中。连接池管理器从指定的 JDBC 驱动器得到一个 Connection ,但在将它返回到应用程序之前,将它与一个也实现 Connection 的虚包包在一起,将自己置入应用程序和底层连接之间。当创建连接或者执行 JDBC 操作时,包装器询问事务管理器当前线程是不是正在事务的上下文中执行,如果事务中有 Connection 的话,就自动征用它。

  其它类型的事务性资源,JMS 消息队列和 JCA 连接器,依靠相似的机制将资源征用隐藏起来,使用户看不到。如果要使 JMS 队列在部署时对 J2EE 应用程序可用,您就要再次使用特定于提供者的机制来创建受管 JMS 对象(队列连接工厂和目标),然后在 JNDI 名称空间内发布这些对象。提供者创建的受管对象包含与 JDBC 包装器(由容器提供的连接池管理器添加)相似的自动征用代码。

     透明的事务控制

  两种类型的 J2EE 事务 ― 容器管理的和 bean 管理的 ― 在如何启动和结束事务上是不同的。事务启动和结束的地方被称为 事务划分(transaction demarcation)。清单 1 中的示例代码演示了 bean 管理的事务(有时也称为 编程(programmatic)事务)。Bean 管理的事务是由组件使用 UserTransaction 类显式启动和结束的。通过 ejbContext 使 UserTransaction 对 EJB 组件可用,通过 JNDI 使其对其它 J2EE 组件可用。

  容器根据组件的部署描述符中的事务属性代表应用程序透明地启动和结束容器管理的事务(或称为 宣告式事务(declarative transaction))。通过将 transaction-type 属性设置为 Container 或 Bean 您可以指出 EJB 组件是使用 bean 管理的事务性支持还是容器管理的事务性支持。

  使用容器管理的事务,您可以在 EJB 类或方法级别上指定事务性属性;您可以为 EJB 类指定缺省的事务性属性,如果不同的方法会有不同的事务性语义,您还可以为每个方法指定属性。这些事务性属性在装配描述符(assembly descriptor)的 container-transaction 部分被指定。清单 2 显示了一个装配描述符示例。 trans-attribute 的受支持的值有:

  Supports

  Required

  RequiresNew

  Mandatory

  NotSupported

  Never

  trans-attribute 决定方法是否支持在事务内部执行、当在事务内部调用方法时容器会执行什么操作以及在事务外部调用方法时容器会执行什么操作。最常用的容器管理的事务属性是 Required 。如果设置了 Required ,过程中的事务将在该事务中征用您的 bean,但如果没有正在运行的事务,容器将为您启动一个。在这个系列的第 3 部分,当您可能想使用每个事务属性时,我们将研究各个事务属性之间的区别。

  清单 2. EJB 装配描述符样本

1 <assembly-descriptor>
2   ...
3   <container-transaction>
4     <method>
5       <ejb-name>MyBean</ejb-name>
6       <method-name>*</method-name>
7     </method>
8     <trans-attribute>Required</trans-attribute>
9   </container-transaction>
10   <container-transaction>
11     <method>
12       <ejb-name>MyBean</ejb-name>
13       <method-name>updateName</method-name>
14       </method>
15    <trans-attribute>RequiresNew</trans-attribute>
16   </container-transaction>
17   ...
18 </assembly-descriptor>
19
  功能强大,但很危险

  与清单 1 中的示例不同,由于有宣告式事务划分,这段组件代码中没有事务管理代码。这不仅使结果组件代码更加易读(因为它不与事务管理代码混在一起),而且它还有另一个更重要的优点 ― 不必修改,甚至不必访问组件的源代码,就可以在应用程序装配时改变组件的事务性语义。

  尽管能够指定与代码分开的事务划分是一种非常强大的功能,但在装配时做出不好的决定会使应用程序变得不稳定,或者严重影响它的性能。对容器管理的事务进行正确分界的责任由组件开发者和应用程序装配人员共同担当。组件开发者需要提供足够的文档说明组件是做什么的,这样应用程序部署者就能够明智地决定如何构建应用程序的事务。应用程序装配人员需要理解应用程序中的组件是怎样相互作用的,这样就可以用一种既强制应用程序保持一致又不削弱性能的方法对事务进行分界。在这个系列的第 3 部分中我们将讨论这些问题。

  透明的事务传播

  在任何类型的事务中,资源征用都是透明的;容器自动将事务过程中使用的任意事务性资源征调到当前事务中。这个过程不仅扩展到事务性方法使用的资源(比如在清单 1 中获得的数据库连接),还扩展到它调用的方法(甚至远程方法)使用的资源。我们来看一下这是如何发生的。

  容器用线程与事务相关联

  我们假设对象 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 演示了事务上下文怎样遵守从 servlet 到 EJB,再到 EJB 的执行路径。

  图 1.单个事务中的多个组件

  

  最优化

  让容器来管理事务允许容器为我们做出某些最优化决定。在图 1 中,我们看到一个 servlet 和多个 EJB 组件在单个事务的上下文中访问一个数据库。每个组件都获得到数据库的 Connection ;很可能每个组件都在访问同一个数据库。即使多个连接是从不同的组件到同一个资源,JTS 也可以检测出多个资源是否和事务有关,并最优化该事务的执行。您可以从第 1 部分回忆起来,单个事务要包含多个资源管理器需要使用两阶段提交协议,这比单个资源管理器使用的单阶段提交代价要高。JTS 能够确定事务中是不是只征用了一个资源管理器。如果它检测出所有与事务相关的资源都一样,它可以跳过两阶段提交并让资源管理器自己来处理事务。

  结束语

  这个虑及透明事务控制、资源征用和透明传播的魔术不是 JTS 的一部分,而是 J2EE 容器如何在幕后代表 J2EE 应用程序使用 JTA 和 JTS 服务的一部分。在幕后有许多实体合力使这个魔术透明地发生;EJB 存根和骨架、容器厂商提供的 JDBC 驱动器包装器、数据库厂商提供的 JDBC 驱动器、JMS 提供器和 JCA 连接器。所有这些实体都与事务管理器进行交互,于是应用程序代码就不必与之交互了。

  在第 3 部分,我们将看一下关于管理 J2EE 上下文中事务的一些实际问题 ― 事务划分和孤立 ― 以及它们对应用程序一致性、稳定性和性能的影响。


本篇文章来源于:开发学院 http://edu.codepub.com   原文链接:http://edu.codepub.com/2009/0423/3289.php
分享到:
评论

相关推荐

    Java理论与实践再研究.pdf

    Java理论与实践再研究的知识点覆盖了Java编程语言的多个重要方面。从基本的入门指南,到深入探讨面向对象的高级特性,再到异常处理、泛型编程和图形用户界面设计,本文件为读者提供了一个系统的学习路径,以深化对...

    Java程序设计研究与实践-理论和实践.pdf

    Java程序设计是一门集理论与实践于一体的计算机编程课程,随着教育技术的发展,传统的教学模式逐渐被网络教学和混合式学习所补充和改变。以下是根据给定文件内容,总结出的Java程序设计在理论和实践方面的知识点。 ...

    JAVA项目实践合集

    "JAVA项目实践合集"是一个综合性的资源集合,包含了多个Java项目的源代码和实践案例,旨在帮助学习者提升Java编程技能并了解实际项目开发过程。这个压缩包中的内容广泛,涵盖了从基础到进阶的各个层面,对于Java初学...

    Java理论与实践:良好的内务处理实践

    这篇文章《Java理论与实践:良好的内务处理实践》着重讨论了Java中对那些需要显式释放的资源进行有效管理的方法。 首先,文章指出,对于诸如文件句柄和套接字这样的资源,不能完全依赖垃圾收集器来回收,因为它们...

    JAVA并发编程实践.pdf

    《JAVA并发编程实践》既能够成为读者的理论支持,又可以作为构建可靠的、可伸缩的、可维护的并发程序的技术支持。《JAVA并发编程实践》并不仅仅提供并发API的清单及其机制,还提供了设计原则、模式和思想模型,使...

    Java理论与实践:变还是不变?

    并说明了在Java理论与实践中,不变性的一些长处、何时使用不变类和构造不变类的一些准则。使用不变对象比使用可变对象要容易得多。它们只能处于一种状态,所以始终是一致的,它们本来就是线程安全的,可以被自由地...

    JAVA程序设计实践

    在“JAVA程序设计实践”这个主题中,我们探讨的是如何通过实际操作来学习和掌握Java编程语言。Java是一种广泛使用的面向对象的编程语言,它的设计理念是“一次编写,到处运行”,这使得它在跨平台应用开发中具有显著...

    Java理论与实践:嗨,我的线程到哪里去了?

    像对付许多风险一样,防止线程泄漏的最佳方法是预防和检测相结合;注意有可能抛出RuntimeException的地方(如调用外来代码时),并使用ThreadGroup提供的uncaughtException处理程序来在线程异常终止时进行检测。

    JAVA并发编程实践.pdf+高清版+目录 书籍源码

    它涵盖了Java并发的核心概念、工具和最佳实践,旨在帮助读者在多线程环境下编写高效、安全的代码。 并发编程是现代软件开发中的关键技能,尤其是在Java这种支持多线程的语言中。Java并发API包括了线程、锁、同步、...

    自考本科 04748 Java语言程序设计 实践报告 示例

    这个实践报告提供了深入理解Java编程的一个实例,帮助学生通过实际操作来巩固理论知识。 在实践报告中,学生可以期待学习以下关键知识点: 1. **Java基础知识**:包括变量、数据类型、运算符、流程控制语句(如if-...

    Java程序设计研究与实践-理论和实践.zip

    本资源“Java程序设计研究与实践-理论和实践.zip”包含了一份深入探讨Java编程的PDF文档,旨在帮助读者从理论到实践全面掌握Java语言。 理论部分,主要涵盖了以下几个关键知识点: 1. **Java语言基础**:包括Java...

    全新java初学者实践教程

    这个全新的Java初学者实践教程将引导你逐步深入Java的世界,通过理论讲解和实例代码,使你在实践中学习和掌握编程技能。记住,实践是检验真理的唯一标准,只有不断动手编写代码,才能真正理解和掌握Java的精髓。祝你...

    高职高专Java课程理论实践教学改革研究.pdf

    总之,通过对高职高专Java课程理论实践教学的改革,可以提高教学质量和效果,培养出更多符合市场需求的Java技术人才。改革需要教师、学校和相关部门共同努力,不断创新和优化教学模式,使教学更加贴合学生的实际情况...

    java并发编程实践(中文版pdf全部40M分2部分上传)2

    《JAVA并发编程实践》既能够成为读者的理论支持,又可以作为构建可靠的、可伸缩的、可维护的并发程序的技术支持。《JAVA并发编程实践》并不仅仅提供并发API的清单及其机制,还提供了设计原则、模式和思想模型,使...

    Java 程序设计与项目实践

    通过这些项目实践,读者可以学习到如何将理论知识转化为实际的代码,提高解决问题的能力,同时也能增强对Java编程的深入理解和应用。配套光盘中的资源将为学习提供辅助,帮助读者更有效地学习和理解Java编程的各个...

    JDK 5.0中的泛型类型学习

    在本月的“Java 理论和实践”中,Brian Goetz 分析了束缚第一次使用泛型的用户的常见陷阱。您可以通过讨论论坛与作者和其他读者分享您对本文的看法。(也可以单击本文顶端或底端的讨论来访问这个论坛。)

    Java Web开发实践教程源码ch10

    在本Java Web开发实践教程源码的第10章中,我们将深入探讨Web应用程序的构建、部署和测试过程。这是一份丰富的学习资源,适用于初学者和有一定经验的开发者,旨在通过实例代码来深化理解Java Web开发的核心概念和...

Global site tag (gtag.js) - Google Analytics