Spring 事务管理

事务分为全局事务和本地事务。

全局事务:是把不同的资源组织在一个事务里管理,(例如数据库操作和消息队列组织在一个事务里)通常使用JTA实现。JTA具有复杂的API,并且JTA中UserTransaction通常使用JNDI获取。这就意味着你需要在JNDI环境下使用全局事务,很明显这种方式降低了代码的可用性,因为JTA通常在应用服务器环境下可用。

本地事务:是针对特定资源操作的事务,也就是说,在事务的整个过程,事务只影响一种资源,事务成功,这种资源状态发生变化,事务失败,资源状态恢复到事务执行前(如数据库操作JDBC事务)。但它有一个严重的不足:它不能做在多事务资源环境下,例如:在jdbc事务下运行的代码,不能在在JTA事务环境下运行。因为应用服务器。因为应用服务器没有与事务管理器关联,它不能保证多个资源在一个事务里(大多数情况,都是单一资源的事务)。另外一个缺陷是使用本地事务是一种侵入式编程,对编程模式有影响。

Spring事务模式:解决了全局事务和本地事务的不足,它采用一致的编程模式使用本地和全局事务。你只需写代码一次,就可以在不同的事务管理策略环境下运行。Spring提供声明式和编程式两种方式使用事务。大多数人喜欢用声明式事务。

使用编程式事务,开发人员只需要学习Spring事务操作方法,使用spring事务编写的代码可以运行在不同的事务环境下。使用声明式事务,开发人员在开发时,不需要关心事务操作的内容。你编写的代码也不依赖于任何Spring事务的API。

Spring事务的介绍

Spring事务的关键是事务策略的概念,spring中事务策略的定义在接口:org.springframework.transaction.PlatformTransactionManager。

public interface PlatformTransactionManager {


TransactionStatus getTransaction(TransactionDefinition definition)


throws TransactionException;


void commit(TransactionStatus status) throws TransactionException;


void rollback(TransactionStatus status) throws TransactionException;
}
 


TransactionException 是继承与java.lang.RuntimeException,在AOP模式下,事务只有捕获java.lang.RuntimeException类的异常才会回滚。

getTransaction(TransactionDefinition)方法,根据参数TransactionDefinition返回TransactionStatus,一个TransactionStatus代表一个新的事务或者是程序上下文中已经存在的事务。已经存在的事务上下文是与当前执行的线程相关联的。

TransctionDefinition 接口定义下列内容:

Isolation: 事务的隔离级别;

Propagation:事务的传播性:通常一个标注事务业务方法方法,运行在一个事务里面,但是,你可以设置propagration改变这种行为。通过设置此值,可以使程序关联上下文中已存在的事物,也可以使用从新启动一个新的事务等行为。

TimeOut:事务开始后,过了设置的时间还没结束,事务会滚。

Read-only status:只读事务用于读取数据而没有修改数据的场景,在某些情况下使用,会带来一定的好处,比如,使用Hibernate。

TransactionStatus接口提供了事务执行控制和查询事务状态的信息。它是提供事务操作的基础APIs:

public interface TransactionStatus extends SavepointManager {


boolean isNewTransaction();


       boolean hasSavepoint();


void setRollbackOnly();


boolean isRollbackOnly();


void flush();


boolean isCompleted();



 


使用Spring时,不论你是否选择声明式事务,还是编程式事务,定义正确的PlatformTransactrionManger的实现类对象都是必须的。通常使用依赖注入的方式定义此对象。

PlatformTransactionManager的实现类对象定义,要结合特定情况,如是使用JDBC,JTA,Hibernate还是其它。下面的例子是定义一个本地的PlatformTransactionManager实现类的定义。

定义JDBC DataSource

< bean id = "dataSource" class = "org.apache.commons.dbcp.BasicDataSource" destroy-method = "close"


< property name = "driverClassName" value = "${jdbc.driverClassName}" />
< property name = "url" value = "${jdbc.url}" />
< property name = "username" value = "${jdbc.username}" />
< property name = "password" value = "${jdbc.password}" />

< /bean >
 


定义PlatformTransactionManager实现类对象,定义时,通过属性名为“dataSource"的引用与上面的数据源关联。

< bean id = "txManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" >


< property name = "dataSource" ref = "dataSource" />
< /bean >
 


如果使用java EE容器里的JTA和DataSource,使用JNDI使JtaTransactionManager和数据源关联在一起。如下面的配置:

< ?xml version="1.0" encoding="UTF-8"? >
< beans xmlns = "http://www.springframework.org/schema/beans"


xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee = "http://www.springframework.org/schema/jee"
xsi:schemaLocation = "
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd" >


< jee:jndi-lookup id = "dataSource" jndi-name = "jdbc/jpetstore" />


< bean id = "txManager" class = "org.springframework.transaction.jta.JtaTransactionManager /〉


< !-- other definitions here -- >


< /beans >
 


JtaTransactionManager不需要指定dataSource,因为它使用容器的全局事务管理器。

HibernateTransactionManager 的配置

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">


<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>


<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">


<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
</bean>


<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">


<property name="sessionFactory" ref="sessionFactory" />
</bean>

 


Hibernate使用JTA

< ?xml version="1.0" encoding="UTF-8"? >
< beans xmlns = "http://www.springframework.org/schema/beans"


xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee = "http://www.springframework.org/schema/jee"
xsi:schemaLocation = "
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd" >


< jee:jndi-lookup id = "dataSource" jndi-name = "jdbc/jpetstore" />


< bean id = "txManager" class = "org.springframework.transaction.jta.JtaTransactionManager /〉

 

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">


<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>


<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">


<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
</bean>

< !-- other definitions here -- >


< /beans >
 


使用事务同步资源

Spring有高水平和低水平两种方式使用事务同步资源。比较好的方式是使用高水平方式。

高水平方式是使用基于持久层APIs或ORM原始APIs的模板,如(JDBCTemplate),这些模板与事务关联,并且内部处理资源的创建、重用、销毁。开发人员使用这些模板编写代码时,不需要关心事务相关的事情,只需关注自己的业务逻辑。

低水平方式,开发人员需要自己使用事务原始APIs管理事务。DataSourceUtils(for jdbc)、EntityManagerFactoryUtils (for JPA), SessionFactoryUtils (for Hibernate), PersistenceManagerFactoryUtils (forJDO)等类是低水平方式下提供事务操作的APIs。例如:在使用传统的jdbc时,使用DataSource的getConnection()获取数据库连接。而使用 DataSourceUtils时,使用下列方式获取连接

Connection conn = DataSourceUtils.getConnection(dataSource);
 


如果程序上下文中存在事务,则返回与此事务关联的连接实例,否则重新创建一个新的连接实例。SQLExeption被CannotGetJdbcConnectionException 包裹,CannotGetJdbcConnectionException是一个RuntimeException。它返回的信息比SQLExeption丰富。更容易定位错误。

这种方法可以不依赖Spring事务管理器运行,在没有事务的环境中也能独立运行。

 

TransactionAwareDataSourceProxy

更低水平的事务应用类,它是一个DataSource的代理类,它能觉察spring事务管理容器中的事务管理器。它与java ee容器管理的DataSource有些类识。

使用声明式事务

声明式事务具有以下特定:

1、可以运行在任何环境下,如jta,jdbc、hibernate、jpa、jdo本地事物。这些功能通过配置就可以完成。

2、声明式事务对业务类的编写不做什么要求,可以用于任何类。

3、Spring提供rollback rules的配置,声明式和编程式事务都可以使用rollback rules

rollback rules 是一个重要的概念,它是用于指定发生什么样的异常,才会引起数据库回滚。你在配置文件里配置它,而不是使用代码设置。注意,能够引起事务回滚的异常必须是RuntimeException类或其子类。

声明式事务是通过AOP动态代理的方式实现,事务的配置数据通过注解或配置文件配置,调用业务方法时,通过代理调用

TransactionInterceptor 拦截器启动事务功能。

使用配置文件使用声明式事务

接口定义:

// the service interface that we want to make transactional


package x.y.service;


      public interface FooService {

Foo getFoo(String fooName);


Foo getFoo(String fooName,ourier"> String barName);


void insertFoo(Foo foo);


      void updateFoo(Foo foo);


}
 


实现类

// an implementation of the above interface


package x.y.service;


public class DefaultFooService implements FooService {


public Foo getFoo(String fooName) {


throw new UnsupportedOperationException();
}


public Foo getFoo(String fooName, String barName) {


throw new UnsupportedOperationException();
}


public void insertFoo(Foo foo) {


throw new UnsupportedOperationException();
}


public void updateFoo(Foo foo) {


throw new UnsupportedOperationException();
}


}
 


配置文件

< !-- from the file 'context.xml' -- >
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"


xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">


< !-- this is the service object that we want to make transactional -- >
<bean id="fooService" class="x.y.service.DefaultFooService"/>


< !-- the transactional advice (what 'happens'; see the 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="*"/>
</tx:attributes>
</tx:advice>


< !-- ensure that the above transactional advice runs for any execution


.1 Reference Documentation 319

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>


< !-- don't forget the DataSource -- >
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>


< !-- similarly, don't forget the PlatformTransactionManager -- >
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>


< !-- other definitions here -- >


</beans>
 

通过注解使用声明式事务

定义接口

// the service class that we want to make transactional
@Transactional

public class
DefaultFooService implements FooService {

Foo getFoo(String fooName);

Foo getFoo(String fooName, String barName);

void insertFoo(Foo foo);

void updateFoo(Foo foo);
}

 配置信息

< !-- from the file 'context.xml' -- >
<
?xml version="1.0" encoding="UTF-8"?>
<
beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop
="http://www.springframework.org/schema/aop"
xmlns:tx
="http://www.springframework.org/schema/tx"
xsi:schemaLocation
="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
>

 < !-- this is the service object that we want to make transactional -- >
 <
bean id="fooService" class="x.y.service.DefaultFooService"/>

 < !-- enable the configuration of transactional behavior based on annotations -- >
 <
tx:annotation-driven transaction-manager="txManager"/>

      < !-- a PlatformTransactionManager is still required -- >
  <
bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <
!-- (this dependency is defined somewhere else) -- >
  <
property name="dataSource" ref="dataSource"/>
  <
/bean>

 < !-- other definitions here -- >

</beans>

 

Property Type Description
value String Optionalqualifierspecifyingthe
  transaction managertobeused.
propagation enum: Propagation Optionalpropagationsetting.
isolation enum: Isolation Optionalisolationlevel.
readOnly boolean Read/write vs. read-only
  transaction
timeout int(insecondsgranularity) Transactiontimeout.
rollbackFor Array of Class objects, which Optional array of exception
 must be derived from classesthat must causerollback.
 Throwable.  
rollbackForClassname Array of class names. Classes Optional array of names of
 must be derived from exception classes that must
 Throwable. causerollback.
noRollbackFor Array of Class objects, which Optional array of exception
 must be derived from classes that must not cause
 Throwable. rollback.
noRollbackForClassname Array of String class names, Optional array of names of
 which must be derived from exception classesthat must not
 Throwable. causerollback.

使用注解方式实现多事务编程

接口定义

< jee:jndi-lookup id = "dataSource" jndi-name = "jdbc/jpetstore" />

< bean id = "txManager" class = "org.springframework.transaction.jta.JtaTransactionManager" />

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值