首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

Spring中的事宜控制学习中(转)

2013-08-27 
Spring中的事务控制学习中(转)1.1.?有关事务(Transaction)的楔子1.1.1.?认识事务本身为了说明“Figure?1.1.

Spring中的事务控制学习中(转)
1.1.?有关事务(Transaction)的楔子1.1.1.?认识事务本身

为了说明“Figure?1.1.?Isolation与Concurrency,Consistency之间的关系


1.1.2.?初识事务家族成员

在一个典型的事务处理场景中,有以下几个参与者:

Figure?1.2.?全局事务示意图


Figure?1.3.?局部事务示意图


Caution

局部事务与全局事务的主要区分在于“1.2.?群雄逐鹿下的Java事务管理1.2.1.?Java平台的局部事务支持

在Java的局部事务场景中,系统中事务管理的具体处理方式会随着所使用的数据访问技术的不同而各异,我们不是使用专用的事务API来管理事务, 而是通过当前使用的数据访问技术所提供的基于“1.2.2.?Java平台的分布式事务支持1.2.2.1.1.?JTA编程事务管理

使用JTA进行分布式事务的编程式事务管理通常使用javax.transaction.UserTransaction接口进行,各应用服务器都提供了针对它的JNDI查找服务。

下面是典型的使用UserTransaction进行事务管理的代码片断:

1.2.2.1.2.?JTA声明性事务管理

如果使用EJB进行声明性的分布式事务管理的话(限于CMT的情况),JTA的使用则只限于EJB容器的内部,对于应用程序来说则完全就是透明的, 现在唯一需要做的工作实际上就是在相应的部署描述符中指定相应的事务属性即可:

1.2.3.?继续前行之前的反思

你也看到了,Java平台提供的事务管理API足够丰富,可谓高中低档一应俱全,这当然有助于我们根据合适场景选用合适的事务管理API, 但,在实际使用过程中,过多的事务管理策略的选择也会造成一些问题:

1.3.?一统河山后的Spring事务管理1.3.1.?spring事务王国的架构Figure?1.4.?普通情况下的事务管理代码


Figure?1.5.?connection-passing方式的事务管理代码


Figure?1.6.?java.sql.Connection绑定到线程示意图


Note

对应Hibernate的SessionFactoryUtils,对应JDO的PersistenceManagerFactoryUtils以及对应其他数据访问技术的Utils类, 他们的作用与DataSourceUtils是相似的,除了提供异常转译功能,他们更多的用于数据访问资源的管理工作,以配合对应的PlatformTransactionManager实现类进行事务管理。

?

实际上,spring在实现针对各种数据访问技术的PlatformTransactionManager的时候要考虑很多的东西,不像原型以及提出的几个问题所展示的那么简单, 不过,各个实现类的基本思路与原型所展示的是基本吻合的,当我们了解了针对Jdbc的PlatformTransactionManager是如何实现的时候,其他的实现类基本上就是平推了。

?

Figure?1.7.?spring事务抽象接口关系图


1.3.1.2.1.?TransactionDefinitionFigure?1.8.?业务方法的传播行为


Figure?1.9.?PROPAGATION_SUPPORTS可能场景


Figure?1.10.?PROPAGATION_REQUIRES_NEW与PROPAGATION_NESTED创建的事务的区别


Figure?1.11.?TransactionDefinition继承层次图


1.3.1.2.2.?TransactionStatus

org.springframework.transaction.TransactionStatus接口定义表示整个事务处理过程中的事务状态, 我们将更多时候在编程式事务中使用该接口。

在事务处理过程中,我们可以使用TransactionStatus进行如下工作:

Figure?1.12.?TransactionStatus继承层次


1.3.1.2.3.?PlatformTransactionManagerTable?1.1.?数据访问技术与PlatformTransactionManager实现类对应关系

数据访问技术PlatformTransactionManager实现类JDBC/iBatisDataSourceTransactionManagerHibernateHibernateTransactionManagerJDOJdoTransactionManagerJPA(Java Persistence API)JpaTransactionManagerTopLinkTopLinkTransactionManagerJMSJmsTransactionManagerJCA Local TransactionCciLocalTransactionManager

Tip

如果你的应用程序需要同时使用Hibernate以及JDBC(或者iBatis)进行数据访问,那么你可以使用HibernateTransactionManager对基于Hibernate和JDBC(或者iBatis)的事务进行统一管理, 只要Hibernate的SessionFactory和JDBC(或者iBatis)引用的是同一个DataSource就行。你能猜到为什么吗?

面向全局事务的PlatformTransactionManager实现类.??org.springframework.transaction.jta.JtaTransactionManager是spring提供的支持分布式事务的PlatformTransactionManager实现。 直接使用JTA规范接口进行分布式事务管理有以下几个问题:

Figure?1.13.?DataSourceTransactionManager的实现层次


Procedure?1.1.?getTransaction(TransactionDefinition)执行流程

    获取transaction object,以判断是否存在当前事务

    ?

    获取Log类的Debug信息,避免之后的代码重复

    ?

    debugEnabled将以方法参数的形式在各方法调用间传递,以避免每次都调用logger.isDebugEnabled()获取debug日志状态。这一步与具体的事务处理流程关系不大。

    ?

    检查TransactionDefinition参数合法性

    ?

    根据先前获得transaction object判断是否存在当前事务,根据判定结果采取不同的处理方式

    ?

    如果isExistingTransaction(transaction)方法返回true,即存在当前事务的情况下

    由handleExistingTransaction()方法统一处理存在当前事务情况下应该如何创建事务对应的TransactionStatus实例并返回。

      如果definition定义的传播行为是PROPAGATION_NEVER,抛出异常并退出

      ?

      如果definition定义的传播行为是PROPAGATION_NOT_SUPPORTED,则挂起当前事务,然后返回

      ?

      如果definition定义的传播行为是PROPAGATION_REQUIRES_NEW,则同样挂起当前事务,并开始一个新的事务并返回

      ?

      AbstractPlatformTransactionManager首先将当前事务挂起,然后调用doBegin()方法开始新的事务,如果开始事务过程中出现异常,则恢复之前挂起的事务。 doBegin(transaction, definition)方法为abstract方法,需要具体子类来实现,在DataSourceTransactionManager中, doBegin()方法会首先检查传入的transaction以提取必要信息判断之前是否存在绑定的connection信息,如果没有,则从DataSource中获取新的connection,然后将其AutoCommit状态改为false,并绑定到TransactionSynchronizationManager。 当然,这期间也会牵扯事务定义的应用以及条件检查等逻辑。 当所有一起搞定之后,newTransactionStatus会创建一个包含definition,transaction object以及挂起的事务信息和其它状态信息的DefaultTransactionStatus实例并返回。

      ?

      如果definition定义的传播行为是PROPAGATION_NESTED,根据情况创建嵌套事务,比如通过Savepoint或者JTA的TransactionManager

      ?

      在这种情况下,会首先通过isNestedTransactionAllowed()方法检查AbstractPlatformTransactionManager的nestedTransactionAllowed属性状态, 如果允许嵌套事务,那么还得分两种情况处理,对于DataSourceTransactionManager来说,因为它支持使用Savepoint创建嵌套事务,所以,会使用TransactionStatus创建相应的Savepoint并返回; 而像JtaTransactionManager则要依赖于具体JTA产品的TransactionManager提供嵌套事务支持。

      ?

      useSavepointForNestedTransaction()方法默认返回true,即默认使用Savepoint创建嵌套事务,如果具体子类不支持使用Savepoint创建嵌套事务,则需要覆写(Override)该方法,比如JtaTransactionManager。

      如果需要检查事务状态匹配情况,则对当前存在事务与传入的defintion中定义的隔离级别与ReadOnly属性进行检查,如果数据不吻合,则抛出异常;

      ?

      剩下的就是其他情况下,直接构建TransactionStatus返回

      比如对应PROPAGATION_SUPPORTS和PROPAGATION_REQUIRED的情况。

      如果isExistingTransaction(transaction)方法返回false,即不存在当前事务的情况下

        当definition中定义的传播行为是PROPAGATION_MANDATORY的时候,抛出异常

        因为不存在当前事务,所以根据PROPAGATION_MANDATORY的语义,理当如此。

        当definition中定义的传播行为是PROPAGATION_REQUIRED或者PROPAGATION_REQUIRES_NEW或者PROPAGATION_NESTED的时候,开启新的事务

        ?

        之所以在doBegin之前先调用传入null的suspend()方法是因为考虑到如果有注册的Synchronization的话,需要暂时将这些与将要开启的新事务无关的Synchronization先放一边。

        ?

        剩下的其他情况,则返回不包含任何transaction object的TransactionStatus并返回

        这种情况下虽然是空的事务,但有可能需要处理在事务过程中相关的Synchronization。

从getTransaction(TransactionDefinition)的逻辑可以看出,AbstractPlatformTransactionManager更多的关注的是事务处理过程的总体逻辑,而跟具体事务资源相关的处理则交给了具体的子类来实现。

事务处理的完成有两种情况,即回滚事务或者提交事务,AbstractPlatformTransactionManager提供的rollback(TransactionStatus)和commit(TransactionStatus)两个模板方法分别对应这两种情况下的处理。 因为事务提交过程中可能需要处理回滚逻辑,我们不妨以commit(TransactionStatus)的实现流程看一下AbstractPlatformTransactionManager是如何处理事务完成的:

Procedure?1.2.?事务提交执行流程

    因为在事务处理过程中,我们可以通过TransactionStatus的setRollbackOnly()方法标记事务回滚,所以,commit(TransactionStatus)在具体提交事务之前会检查rollBackOnly状态, 如果该状态被设置,那么转而执行事务的回滚操作;

    rollback(TransactionStatus)的逻辑主要包含三点:

    Figure?1.14.?模板类与实现类之间的纽带


    1.3.2.?使用spring进行事务管理1.3.2.1.1.?直接使用PlatformTransactionManager进行编程式事务管理

    PlatformTransactionManager接口定义了事务界定的基本操作,我们可以直接使用PlatformTransactionManager进行编程式事务管理:

    1.3.2.1.2.?使用TransactionTemplate进行编程式事务管理

    org.springframework.transaction.support.TransactionTemplate对与PlatformTransactionManager相关的事务界定操作以及相关的异常处理进行了模板化封装, 开发人员更多的关注于通过相应的callback接口提供具体的事务界定内容即可。spring针对TransactionTemplate提供了两个callback接口,TransactionCallback和TransactionCallbackWithoutResult,二者的唯一区别就是是否需要返回执行结果。

    使用TransactionTemplate进行事务管理的代码看起来要比直接使用PlatformTransactionManager要简洁并且容易管理的多:

    1.3.2.1.3.?编程创建基于Savepoint的嵌套事务

    TransactionStatus不但可以在事务处理期间通过setRollbackOnly()方法来干预事务的状态,如果需要,作为SavepointManager,它也可以帮助我们使用Savepoint机制创建嵌套事务。

    我们以银行账户间转账为例说明如何使用TransactionStatus创建基于Savepoint的嵌套事务,不过,现在不是从一个账户转到另一个账户,而是从一个账户转到两个账户,一个是主账户,一个备用帐户,如果向主帐户转账失败,则将金额转入备用帐户,总之,金额从第一个账户取出之后,必须存入两个账户的其中一个,以保证整个事务的完整性。 在这样的前提下,我们的事务管理代码基本上如下所示:

    Note

    使用TransactionStatus创建基于Savepoint的嵌套事务需要底层的PlatformTransactionManager实现类的支持,当前只有在JDBC3.0驱动下的DataSourceTransactionManager可用。

    通过使用TransactionStatus创建基于Savepoint的嵌套事务并非创建嵌套事务的唯一方式,也并非最方便的方式,实际上,我们更倾向于结合PROPAGATION_NESTED传播行为的声明式事务管理方式。

    1.3.2.2.1.?引子

    声明式事务实际上并没有想象中的那么神秘,当我们将“Figure?1.15.?TransactionFacade场景示意图


    Tip

    啥?我还没有公布第二个问题是如何解决的?还记得在TransactionDefinition部分提到的用于声明式事务的TransactionAttribute定义吗? 其实仅需要将“1.3.2.2.2.?XML元数据驱动的声明式事务QuoteSerivceClient是一般意义上使用QuoteService的应用类,当我们通过它调用QuoteService的业务方法的时候,除了getQuote()方法之外,其他方法(比如getQuoteService().saveQuote(quote))因为抛出了“要对数据资源进行访问,QuoteService采用的是JDBC的方式,即直接使用spring提供的JdbcTemplate,那么,我们需要提供JdbcTemplate以及特定于Jdbc的事务管理器(DataSourceTransactionManager):

    数据访问技术与事务管理器的类型是一一对应的,否则就有“TransactionInterceptor所需要的业务对象上每个业务方法的事务管理信息通过org.springframework.transaction.interceptor.TransactionAttributeSource接口来获取:

    Note

    也可以通过transactionAttributeSources属性指定元数据信息,它是transactionAttributeSource的复数形式

    ?

    当TransactionInterceptor准备就绪之后,剩下的就是通过spring的AOP将业务对象与其绑定就可以了:
    只不过,一定不要把“

    元数据中事务属性指定规则

    以String形式给出的事务属性是有一定规则的,这个规则由org.springframework.transaction.interceptor.TransactionAttributeEditor类的逻辑来界定, TransactionAttributeEditor负责将String形式给出的事务属性转换为具体的TransactionAttribute实例(RuleBasedTransactionAttribute)。

    String形式的事务属性规则如下:

    现在,TransactionProxyFactoryBean集ProxyFactoryBean,TransactionInterceptor功能于一身,一心一意的为声明式事务管理做贡献了。

    ?

    不过,你也看到了,针对TransactionProxyFactoryBean的bean定义看起来不是那么苗条,如果每一个需要声明式事务的业务对象都来这么一下子, 那配置量可着实不轻松,所以,通常情况下,我们会使用bean定义模板的方式来简化使用TransactionProxyFactoryBean进行声明式事务的配置:

    将共有的一些属性提取到“现在,我们只需要正常的向IoC容器的配置文件中追加相应的业务对象bean定义即可,BeanNameAutoProxyCreator将根据TransactionInterceptor提供的事务管理功能自动为添加到它的“<tx:advice>是专门为声明事务Advice设置的配置元素,底层当然还是我们的TransactionInterceptor,仅仅是披一件新衣裳而已。 <tx:advice>的“Table?1.2.?<tx:method/>属性对照表

    属性名说明name事务元数据将要加诸于上的业务方法名称,可以使用*通配符。propagation事务的传播行为,不明确指定的话,默认值为REQUIRED,你会发现,该名称去掉了TransactionDefintion中常量名称的前缀,在指定的时候,需要注意。isolation用于指定事务的隔离度,不明确指定,默认值采用DEFAULT,也是TransactionDefintion中常量名称去掉前缀。timeout事务的超时时间,默认值为-1。read-only指定事务是否为只读事务,默认值为false;rollback-for用于指定能够触发事务回滚的异常类型,比如rollback-for=“在SpringAOP一章我们已经说过,<aop:config>底层也是依赖于自动代理(Autoproxy)机制,所以,我一直强调,新的基于XSD的配置方式仅仅是换了一身简洁明快的外衣, 而我想让大家看到的是外衣里面的东西。

    ?

    Note

    更多使用<tx:advice>的内容可以参照spring2.x之后的参考文档,其中有更多详细内容,比如配置多个<tx:advice>以区分不同的事务需求等内容。

    1.3.2.2.3.?Annotation元数据驱动的声明式事务

    随着Java5(Tiger)的发布,Annotation越来越受到开发人员的关注和喜爱,如果你的应用程序构建于Java5或者更高版本的虚拟机之上的话,那么恭喜你,现在你也可以使用Spring提供的基于Annotation的声明式事务管理啦[12]。

    Annotation元数据驱动的声明式事务管理的基本原理是,将对应业务方法的事务元数据直接通过Annotation标注到业务方法或者业务方法所在的对象之上, 然后在业务方法执行期间,通过反射(Reflection)读取标注在该业务方法之上的Annotation所包含的元数据,最终将根据读取的信息为业务方法构建事务管理的支持。

    spring定义了org.springframework.transaction.annotation.Transactional用于标注业务方法所对应的事务元数据信息,通过Transactional,我们可以指定与<tx:method/>几乎相同的信息,当然,现在不用指定方法名称了, 因为Transactional直接标注到了业务方法或者业务方法所在的对象定义之上。通过查看Transactional的定义,我们可以获取所有可以指定的事务定义内容:

    至此,基于Annotation的声明式事务就算大功告成了。

    ?

    Tip

    spring推荐将@Transactional标注于具体的业务实现类或者实现类的业务方法上, 之所以如此,是因为spring aop可以采用两种方式来生成代理对象(dynamic proxy 或者cglib)。 如果将@Transactional标注于业务接口的定义上,那么,当使用Dynamic proxy机制构建代理对象的时候,读取接口定义上的@Transactional信息是没有问题的; 可是当使用CGLIB构建代理对象的时候,则无法读取接口上定义的@Transactional数据。

    1.4.?spring事务管理之扩展篇1.4.1.?理解并活用ThreadLocalFigure?1.16.?公交线路和车站与线程和ThreadLocal之间的类比示意图


    Figure?1.17.?ThreadLocal功能分析图


    Procedure?1.3.?基于ThreadLocal管理多数据源切换条件的AbstractRoutingDataSource实现流程

      假设我们有MAIN,INFO和DBLINK三个数据源可用,第一步要做的事情就是先给出一个枚举类, 其中定义了对应这三个数据源的标志:

      注意,我们在配置ThreadLocalVariableRountingDataSource所使用的多个目标数据源的时候,使用了<map>的key-type属性指明了键值的类型, 否则,你得通过其他的方式来确定枚举类的各值作为key与目标数据源之间的对应关系。

      ?

      万事俱备之后,你可以使用如下代码使得数据源的切换生效:

      1.4.2.?谈Strategy模式在开发过程中的应用

      Strategy模式的本意是封装一系列可以互相替换的算法逻辑,使得具体算法的演化独立于使用它们的客户端代码。 为了理解为什么要这么做,我们不妨来看一个具体的场景:

      在一个信贷系统中,通常会提供多种还款方式,比如等额本金还款方式,等额本息还款方式,一次还本付息方式等等, 那么,针对每一位顾客所选择的还款方式,我们就需要按照这些还款方式的具体逻辑为顾客计算每次所需要归还的本金以及利息的额度, 如果要我们来实现这个根据还款方式计算额度的逻辑,我们会怎么做那?

      对于谙熟结构化编程或者面向对象编程不甚娴熟的开发人员来说,他们可能会直接使用多重条件语句来实现这段计算逻辑:
      Figure?1.18.?RepaymentStrategy场景图


      Tip

      除了使用ioc容器注入映射关系,你还可以将对应应用程序的映射关系放到数据库或者其他外部配置文件,甚至Annotation中。 通过ioc容器一次注入多个策略实例可能需要占用多一些的系统资源,对于资源紧要的应用来说,可以考虑通过反射等方式按需构建具体策略实例,这个就留给读者来完成吧!

      ?

      在系统中合理的使用Strategy模式可以使得系统向着“1.4.3.?Spring与JTA背后的奥秘(Magic behind Spring and JTA)

      无论是spring的参考文档还是大多数介绍spring的书籍在提到使用Spring的JtaTransactionManager进行分布式事务管理的时候, 都强调需要使用从应用服务器的JNDI服务获取的dataSource,而不是本地配置的普通dataSource:

      Figure?1.19.?JtaTransactionManager和DataSource之间的是与非


      从常识上来讲,像DataSourceTransactionManager这样才是正常的情况, 而我们也看到JtaTransactionManager确实没有明确指定依赖于哪一个资源,却依然能够将需要加入分布式事务的资源纳入其管理范围,那么,它是怎么做到的那? 如果揭开这个谜团,是否就能搞清楚当使用JtaTransactionManager的时候,要求我们使用从应用服务器的JNDI服务查找到的DataSource的真正原因那?

      ?

      在介绍JtaTransactionManager的时候,我们说到JtaTransactionManager只是对各种具体的JTA实现产品提供的分布式事务管理功能进行了封装, 最终的工作JtaTransactionManager都会委派给具体的JTA实现来做,所以,追根溯源,我们不得不追到JTA规范以及JTA实现中去。

      略去JTA以及X/Open规范千言不提,我们还是长话短说,直接进入正题吧![14]

      首先,具体的事务资源(RDBMS,MessageQueue,etc)要加入JTA管理的分布式事务,JTA规范要求其实现javax.transaction.xa.XAResource接口, 所以,希望加入JTA管理的分布式事务的资源管理器(RM)通常会提供相应的适配器(Adaptor)用于提供基于XAResource的分布式事务交互能力,比如关系数据库提供的支持XA的JDBC驱动程序就属于这样的适配器(Adaptor)。 这样,所有资源管理与事务交互的工作基本上就由RM的Adaptor来统一管理啦。

      当想要参与JTA分布式事务的事务资源拥有了XAResource支持之后,JTA的javax.transaction.TransactionManager(我们称其为JTA TransactionManager,区别于spring的JtaTransactionManager)与RM之间就可以进行通信:

      Figure?1.20.?TM与RM之间的通信


      Procedure?1.4.?ApplicationServer内部的运作

        ApplicationServer一开始当然要先通过JNDI绑定它的JTA实现中的UserTransaction或者TransactionManager具体实现类, 这样,客户端应用程序就可以通过JNDI获取他们。现在客户端应用程序想要开始一个分布式事务,进而UserTransaction或者TransactionManager的相应方法被调用;

        ApplicationServer内部会要求TransactionManager为当前事务分配一个唯一的标志(以Xid表示),然后开始事务,并将当前事务绑定到当前线程;

        客户端跟ApplicationServer要求相应的数据资源进行数据访问,ApplicationServer会跟RM的Adaptor要一个事务资源对象,我们暂且称之为TransactionalResource,该资源对象包含两部分,一部分是JTA TransactionManager需要与之交互的XAResource,另一部分是要暴露给客户端应用程序使用的Connection资源, 取得TransactionalResource之后,ApplicationServer要做两件事情:

          ApplicationServer从TransactionalResource中取得XAResource给TransactionManager,TransactionManager开始通过获得的这个XAResource与RM进行交互, 实际上,现在TransactionManager只是调用XAResource的start(xid)方法通知RM开始记录;

          ApplicationServer然后再把跟XAResource属于Figure?1.21.?ApplicationServer暴露的Connection


          我们需要告知Spring的JtaTransactionManager使用Atomikos的UserTransaction和TransactionManager实现,而至于Atomikos的UserTransaction和TransactionManager到底如何与RM(database, messsage queue,etc)进行交互,那就是Atomikos的事情了。

          Note

          不要被Atomikos的SimpleDataSourceBean的名字给迷惑了,另外,只要你的数据库提供了有XA支持的数据库驱动,你就可以通过SimpleDataSourceBean来配置需要的支持XA的DataSource,但各个参数的设置需要参考相应驱动程序的文档, 比如xaDataSourceClassName以及xaDataSourceProperties属性。

          多个Atomikos的SimpleDataSourceBean存在的情况下,他们对应的uniqueResourceName必须是不同的!!!

          ?

          最后的内容是专门为spring的JtaTransactionManager的,2.5版本的spring发布后,在XSD的配置中,可使用tx命名空间下专门为JtaTransactionManager提供的配置元素来简化其配置:

          <tx:jta-transaction-manager/>
          当然,如果需要,也可以通过内嵌的<property>指定使用自定义的UserTransaction或者TransactionManager。

          ?


          [1]?这里的“正确”有所泛指,比如,系统状态需要始终完整,各项数据的关系始终保持一致等等,当系统各项状态以合理的形式存在的时候,那我们说系统处于一个正确的状态,这样的表达方式我想应该可以接受吧?!

          [2]?也可称为“隔离度”,大家只需要知道我们指的都是Isolation这个概念就可以。

          [3]?又称“幻影读”。

          [4]?更确切的说是JTA(Java Transaction API)以及JTS规范(Java Transaction Service Specification)

          [5]?事务界定规定了一个事务什么时候开始以及什么时候结束

          [6]?事务的上下文传播指的是,在整个事务处理工程中,如何在各事务操作之间传播事务信息的行为。

          [7]?这里的connection不是特指java.sql.Connection类型,而是泛指应用程序与事务资源之间的通信通道,对于JDBC来说,恰好对应java.sql.Connection,如果是Hibernate,那就应该是Session,诸如此类

          [8]?实际上,你可以通过配置来决定让Hibernate使用基于Jdbc Connection的局部事务管理,还是让Hibernate使用分布式的事务管理。

          [9]?当然,如果只是检测单条数据插入的主键冲突,然后改为更新数据的话,更多时候,我们会直接在一个数据访问方法中搞定。

          [10]?因为UML的Sequence图对于条件判断等逻辑无法以恰当的方式表示,而Activity图整个表示下来过大,不便显示,所以,最后决定以文字描述的方式进行。

          [11]?实际上,只要有一个支持XSD的XML编辑器,对于我们来说根本就不用记住每一个属性的具体特征,通常这种编辑器都会有提示功能, 只要提示的每个属性你知道它具体代表什么意思,剩下的就是个选择的问题。

          [12]?当然,即使你不使用Java5,也不意味着你不能使用源码中的元数据驱动的声明式事务,比如你可以使用commons attributes(http://commons.apache.org/attributes/),但是, Java5的Annotation可以为我们带来更多的东西,比如编译器检查,IDE良好的重构支持等等。 如果当前应用无法使用Java5,而又要使用源代码中元数据驱动的声明式事务,你可以参照spring参考文档中提供的使用commons attributes的相关信息。

          [13]?在《Java多线程设计模式》一书中,对“Thread-Specific Storage Pattern”有详细的介绍和讲解。

          [14]?实际上JTA规范本身不到100页,想要更深入的了解JTA的内容的话,看一下也无妨啊!

热点排行