Spring框架事务支持模型的优势
2016-05-15 19:54
411 查看
全局事务
全局事务支持对多个事务性资源的操作,通常是关系型数据库和消息队列。应用服务器通过JTA管理全局性事务,API非常烦琐。UserTransaction通常需要从JNDI获取,意味着需要与JNDI绑定在一起,且JTA一般只在应用服务器可用,降低了应用代码的可重用性。本地事务
本地事务面向具体的资源,例如与JDBC连接关联的事务。本地事务易于使用,但不能跨多个事务性资源。使用JDBC管理事务的代码不能在全局JTA事务中运行,因此不能确保跨多个资源的正确性。且本地事务侵入了编程模型。Spring的一致性编程模型
Spring让开发者在任何环境下都可以使用一致性的编程模型,编写一次代码,就可以在不同环境的不同事务管理策略中运行。Spring提供声明式和编程式事务管理,大多数人选择声明式,这也是推荐的方式。使用编程式事务管理时,开发者使用的是Spring框架的事务抽象,它可以运行在任何底层事务设施之上。使用声明式事务管理,开发者只需要编写少量甚至不需要编写事务相关代码,因此应用代码不依赖Spring框架事务API或其它事务API。
Spring的事务管理支持从传统规则到应用服务器的转换。
通常只有在通过EJB进行声明式事务时才真的需要应用服务器。实际上即使应用服务器有JTA的功能,也可以认为Spring框架的声明式事务比EJBCMT更加强大,更加能提高效率。
只有在应用需要跨多个资源处理事务时才需要应用服务器的JTA功能。许多高级应用使用单个高可扩展的数据库(例如OracleRAC)来代替。独立的事务管理器也是一种方案,例如AtomikosTransactions、JOTM。应用也可能需要其它的应用服务器功能,例如JMS、JCA。
Spring框架让开发者决定何时把应用扩展为完整的应用服务器,只需要在配置文中修改某些Bean定义即可。
理解Spring框架的事务抽象
事务策略是Spring事务抽象的关键。事务策略由org.springframework.transaction.PlatformTransactionManager接口定义:TransactionStatusgetTransaction(TransactionDefinitiondefinition)throwsTransactionException;
voidcommit(TransactionStatusstatus)throwsTransactionException;
voidrollback(TransactionStatusstatus)throwsTransactionException;
}
TransactionException是作为非检查异常抛出,它扩展java.lang.RuntimeException类,因为在Spring的角度看来,事务设施故障几乎总是致命的,很少情况下应用可以从事务故障中恢复。开发者可以选择捕获这个异常并作处理,但并不强制这样做。
getTransaction(…)根据TransactionDefinition类型的参数返回一个TransactionStatus对象,所返回的对象可能代表一个新的事务,也可能是一个当前调用栈中已经存在的事务。后一种情况表示,在使用JavaEE事务上下文时,一个TransactionStatus是与执行线程关联的。
TransactionDefinition接口
TransactionDefinition接口指定了:隔离级别(Isolation):一个事务与其它事务的隔离级别,例如一个事务是否可看到其它事务未提交的写操作
传播性(Propagation):一般所有在一个事务中运行的代码都会处于一个事务中,但当执行一个方法并且事务环境已经存在时,可以指定此时的行为。例如所调用方法内的代码继续运行在已经存在的事务中(常见情况),或者暂停当前事务并创建一个新的事务来运行所调用方法内的代码。Spring提供了所有EJBCMT所提供的事务传播选项。
超时(Timeout):在事务超时并被底层事务设施自动回滚前,这个事务可以运行多久。
只读状态(Read-only):当代码不修改数据时,可以使用只读事务。只读事务在某些场景下很有用,例如使用Hibernate时。
以上设置是标准的事务概念,指的就是事务隔离级别及其它核心事务概念。理解这些概念是使用Spring框架事务管理或其它事务解决方案的基础。
TransactionStatus接口
TransactionStatus接口为事务性代码提供控制事务执行和查询事务状态的简便方式。这些概念必须要熟悉,它们是所有事务API都共同的东西:booleanisNewTransaction();
booleanhasSavepoint();
voidsetRollbackOnly();
booleanisRollbackOnly();
voidflush();
booleanisCompleted();
}
PlatformTransactionManager一般只需要知道自己的工作环境:JDBC、JTA、Hibernate等等。下面是定义一个本地PlatformTransactionManager实现的例子:
定义JDBC数据源:
<beanid="dataSource"class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close"> <propertyname="driverClassName"value="${jdbc.driverClassName}"/> <propertyname="url"value="${jdbc.url}"/> <propertyname="username"value="${jdbc.username}"/> <propertyname="password"value="${jdbc.password}"/> </bean>
相关的PlatformTransactionManager引用DataSource定义:
<beanid="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <propertyname="dataSource"ref="dataSource"/> </bean>
如果在JavaEE容器中使用容器DataSource,则通过JNDI获取,并与Spring的JtaTransactionManager关联:
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="
xmlns:xsi="
xmlns:jee="
xsi:schemaLocation="
<jee:jndi-lookupid="dataSource"jndi-name="jdbc/jpetstore"/>
<beanid="txManager"class="org.springframework.transaction.jta.JtaTransactionManager"/>
<!--other<bean/>definitionshere-->
</beans>
Hibernate事务配置
<beanid="sessionFactory"class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<propertyname="dataSource"ref="dataSource"/>
<propertyname="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<propertyname="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
</bean>
<beanid="txManager"class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<propertyname="sessionFactory"ref="sessionFactory"/>
</bean>