Understanding Transaction

主要由Spring和EJB Container处理transaction来理解如何handle transaction.

一. Local Transaction

Spring里实现database的事物需要,
1. 声明transaction manager
普通JDBC
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
</bean>

Hibernate
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory" />
</bean>

JPA
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

JTA 以后会介绍JTA的transaction
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>

2. 声明tx:advice
这是用来声明事物的隔离级别和回滚规则的
<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
  <tx:advice id="txAdvice" transaction-manager="txManager">
  <!-- the transactional semantics... -->
  <tx:attributes>
    <!-- all methods starting with 'get' are read-only -->
    <tx:method name="get*" read-only="true" />
    <!-- other methods use the default transaction settings (see below) -->
    <tx:method name="update*" rollback-for="NoProductInStockException"/>
  </tx:attributes>
  </tx:advice>

3. 声明aop 来拦截service方法同时应用tx:advice
<!-- ensure that the above transactional advice runs for any execution
    of an operation defined by the FooService interface -->
  <aop:config>
  <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
  </aop:config>

2.3 是XML based transaction声明方式,transaction也可以通过annotation来实现,即使用
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="txManager"/>
然后使用@Transactional在方法上进行注解来实现。

EJB 事物声明 中的

Required
   将在有效的事务上下文中调用 EJB 方法。如果方法被已经拥有事务上下文的客户机调用,那么 EJB 方法会在那个事务内执行。如果方法不是在现有的事务上下文中被调用,那么要启动新的事务并执行 EJB 方法。当 EJB 方法完成时 EJB 容器自动尝试提交事务。

RequiresNew和 Required
   的相似之处在于,EJB 方法要在事务上下文中执行。但是,这种方法会始终在新的上下文中执行。因此,如果这种方法被已有事务上下文的客户机调用,那么会暂挂现有的事务且启动新的事务。当 EJB 方法完成后,容器会自动提交事务并继续执行暂挂的事务。

NotSupported
   EJB 方法会被“未指定的事务上下文”所调用。事务语义可能根据所使用的容器实现(也就是说,供应商产品)的不同而不同。

Supports
   特定的操作会根据 EJB 客户机事务上下文的不同而不同。如果客户机已有事务上下文,那么这种情况的处理和 Required的处理方式一样。如果客户机缺少事务上下文,那么这种情况的处理和 NotSupported中的处理方式一样。

Mandatory
EJB 方法必须在客户机的事务上下文中被调用。如果客户机缺乏事务上下文,那么容器抛出异常。如果客户机有事务上下文,那么这种情况的处理和 Required中的处理方式一样。

Never
   特定的操作会根据 EJB 客户机的操作上下文的不同而不同。如果客户机有事务上下文,那么容器抛出异常。如果客户机缺少事务上下文,那么这种情况的处理和 NotSupported的处理方式一样。

另外,会话 bean 程序员可以将他们的事务声明为 BeanManaged 并编写使用 javax.transaction.UserTransaction 接口(Java 事务 API(Java Transaction API)的一部分)的代码,以此为事务的开始和结束划分界线。但是,许多 EJB 架构设计师尽量避免使用 bean 管理的事务,除非特定的业务需求规定他们这么做。允许 EJB 容器使事务管理自动化能够减少编码和测试要求。这里我们将只考虑容器管理的事务。

值得注意的是:
Although EJB container default behavior automatically rolls back the transaction on a system exception (usually a runtime exception), EJB CMT does not roll back the transaction automatically on an application exception (that is, a checked exception other than java.rmi.RemoteException). While the Spring default behavior for declarative transaction management follows EJB convention (roll back is automatic only on unchecked exceptions), it is often useful to customize this behavior.
也就是说EJB Container会对RuntimeException进行Rollback操作,但是对checked exception却不会主动Rollback.

二. Global Transaction
Global Transaction是指在分布式系统中同时访问多个不同Resource 比如同时访问DB,JMS,和FileSystem,需要保证各个transaction在满足local transaction的同时互相aware其他resource,以此保证整个事物的ACID。

JTA(http://www.jcp.org/en/jsr/detail?id=907)对这样的事物操作进行了很好的定义,
下面一片文章是对JTA处理Gloabal Transaction的细节
http://archive.devx.com/java/free/articles/dd_jta/jta-2.asp

回想一下Local Transaction是如何支持事物的?在某一时刻提交对数据库的所有改动,而对于任何的异常实行Rollback操作。这种操作可以看作在数据库里执行了所有的修改操作,由数据库来保证事物。对JTA正是把这样的思想进行扩展,它制造了一个在Application Server和Data Source之间的层次,即Transaction Manager,所有的提交是对Transaction Manager的操作,而事物也是在Transaction Manager里保证。

各种J2EE容器对JTA都有支持,每个global的对象可以看作xa对象。如果使用的datasource已经实现了XAResource,比如Jackrabbit Session,那么可以通过Transaction.enlist(xaResource)来快速的把当前操作的对象关联到当前Transaction上。

Spring中,可以通过
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
生命JTA Transaction Manager,但是如果仅仅这样声明,意味着这段代码必须出现在J2EE容器中,它表示使用容器托管JTA事物。如果使用的是Tomcat之类的非J2EE容器,也可以通过声明第三方JTA容器,例如jotm,例子如下
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/>   
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"> 
         <property name="userTransaction" ref="jotm"/>
</bean>  

声明了JTA TransactionManager之后可以在DAO中引用来关联自己的XAResource,
tansactionManager.getTransactionManager().getTransaction().enlistResource(new MyXa());

EJB中需要得到Transaction Manager来关联自己的XAResource,但是各个EJB容器对TransactionManager的支持却并不相同,
http://onjava.com/onjava/2005/07/20/transactions.html 给出各个容器获得TransactionManager的方式。
http://docs.oracle.com/cd/E18930_01/html/821-2418/gaxit.html 给出GlassFish得到TransactionManager的方式,即
@Resource(name="java:appserver/TransactionManager")
TransactionManager tm;
然后可以使用tm.getTransaction().enlistResource(new MyXa());来关联XAResource。

如果所使用的DataSource并没有得到XAResource的方法, 那么或许可以通过
http://commons.apache.org/transaction/ 来实现(待证明)
,也可以手动管理事物来实现。

EJB里可以通过,context是EJBContext,
UserTransaction ut = context.getUserTransaction();

      try {
         ut.begin();
         // Do whatever transaction functionality is necessary
         ut.commit();
      } catch (Exception ex) {
          try {
             ut.rollback();
          } catch (SystemException syex) {
              throw new EJBException
                 ("Rollback failed: " + syex.getMessage());
          }
          throw new EJBException
             ("Transaction failed: " + ex.getMessage());
       }  
来管理事物的边界。



三. test-jpa包含jpa 2.0 feature和 JTA EJB的使用
test-jpa-web包含JPA和Spring的各种使用



你可能感兴趣的:(transaction)