Spring2.0简明手册(系列之五 事务管理)

1.声明式事务管理
    Spring2.0及以后的版本中声明式事务的配置与之前的版本有相当大的不同。主要差异在于不再需要配置TransactionProxyFactoryBean了。
1.1基于XML Schema
//我们想做成事务性的服务接口
package x.y.service;

public interface FooService {
    Foo getFoo(String fooName);
    Foo getFoo(String fooName, String barName);
    void insertFoo(Foo foo);
    void updateFoo(Foo foo);
}

//上述接口的一个实现
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();
    }
}
     <? 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="
           [url]http://www.springframework.org/schema/beans[/url] [url]http://www.springframework.org/schema/beans/spring-beans-2.0.xsd[/url]
           [url]http://www.springframework.org/schema/tx[/url] [url]http://www.springframework.org/schema/tx/spring-tx-2.0.xsd[/url]
           [url]http://www.springframework.org/schema/aop[/url] [url]http://www.springframework.org/schema/aop/spring-aop-2.0.xsd[/url]" >

        <!-- =================================== -->
        <!--                          加载属性文件                        -->
        <!-- =================================== -->
         < bean id ="jdbcConfiguration"
             class ="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
             < property name ="locations" >
                 < list >
                     < value >classpath:jdbc-config.properties </ value >
                 </ list >
             </ property >
         </ bean >
        <!-- =================================== -->
        <!--                          配置数据源                          -->
        <!-- =================================== -->
       < 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 >

       < bean id ="txManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
         < property name ="dataSource" ref ="dataSource" />
       </ bean >

        <!-- =================================== -->
        <!--                          配置事务                            -->
        <!-- =================================== -->
         < aop:config >
             < aop:pointcut id ="defaultServiceOperation" expression ="execution(* x.y.service.*Service.*(..))" />
             < aop:advisor pointcut-ref ="defaultServiceOperation" advice-ref ="defaultTxAdvice" />
             < aop:pointcut id ="noTxServiceOperation" expression ="execution(* x.y.service.ddl.DefaultDdlManager.*(..))" />
             < aop:advisor pointcut-ref ="noTxServiceOperation" advice-ref ="noTxAdvice" />
         </ aop:config >

         < tx:advice id ="defaultTxAdvice" transaction-manager ="txManager" >
             < tx:attributes >
                 < tx:method name ="get*" read-only ="true" />
                 < tx:method name ="*" />
             </ tx:attributes >
         </ tx:advice >

         < tx:advice id ="noTxAdvice" transaction-manager ="txManager" >
             < tx:attributes >
                 < tx:method name ="*" propagation ="NEVER" />
             </ tx:attributes >
         </ tx:advice >

        <!-- =================================== -->
        <!--                          配置业务Bean                        -->
        <!-- =================================== -->
        <!--
       this bean will be transactional (c.f. the 'defaultServiceOperation' pointcut)
      -->
         < bean id ="fooService" class ="x.y.service.DefaultFooService" />

        <!-- this bean will also be transactional,
           but with totally different transactional settings -->
         < bean id ="anotherFooService" class ="x.y.service.ddl.DefaultDdlManager" />
     </ beans >

    更进一步:参照Spring2.0参考手册--9.5.5. <tx:advice/> 有关的设置

1.2使用 @Transactional
    //the service class that we want to make transactional
    @Transactional(readOnly = true)
    public class DefaultFooService implements FooService {

        public Foo getFoo(String fooName) {
            // do something
        }

        // these settings have precedence for this method
        @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
        public void updateFoo(Foo foo) {
            // do something

        }
    }

     <? 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:tx ="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="
           [url]http://www.springframework.org/schema/beans[/url] [url]http://www.springframework.org/schema/beans/spring-beans-2.0.xsd[/url]
           [url]http://www.springframework.org/schema/tx[/url] [url]http://www.springframework.org/schema/tx/spring-tx-2.0.xsd[/url]" >

        <!-- =================================== -->
        <!--                          加载属性文件                        -->
        <!-- =================================== -->
         < bean id ="jdbcConfiguration"
             class ="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
             < property name ="locations" >
                 < list >
                     < value >classpath:jdbc-config.properties </ value >
                 </ list >
             </ property >
         </ bean >

        <!-- =================================== -->
        <!--                          配置数据源                          -->
        <!-- =================================== -->
       < 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 >

       < bean id ="txManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
         < property name ="dataSource" ref ="dataSource" />
       </ bean >

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

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


    更进一步:参照Spring2.0参考手册--9.5.6.1. @Transactional 有关的设置

1.3插入事务操作

    1.3.1使用 @Transactional
    <!-- the service class that we want to make transactional -->
    @Transactional(readOnly = true)
    public class DefaultFooService implements FooService {

        public Foo getFoo(String fooName) {
            // do something
        }

        // these settings have precedence for this method
        @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
        public void updateFoo(Foo foo) {
            // do something

        }
    }

package x.y;

import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;
import org.springframework.core.Ordered;

public class SimpleProfiler implements Ordered {

    private int order;

    // allows us to control the ordering of advice
    public int getOrder() {
        return this.order;
    }

    public void setOrder(int order) {
        this.order = order;
    }

    // this method is the around advice
    public Object profile(ProceedingJoinPoint call) throws Throwable {
        Object returnValue;
        StopWatch clock = new StopWatch(getClass().getName());
        try {
            clock.start(call.toShortString());
            returnValue = call.proceed();
        } finally {
            clock.stop();
            System.out.println(clock.prettyPrint());
        }
        return returnValue;
    }
}

<? 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="
   [url]http://www.springframework.org/schema/beans[/url] [url]http://www.springframework.org/schema/beans/spring-beans-2.0.xsd[/url]
   [url]http://www.springframework.org/schema/tx[/url] [url]http://www.springframework.org/schema/tx/spring-tx-2.0.xsd[/url]
   [url]http://www.springframework.org/schema/aop[/url] [url]http://www.springframework.org/schema/aop/spring-aop-2.0.xsd[/url]" >

     < bean id ="fooService" class ="x.y.service.DefaultFooService" />

    <!-- this is the aspect -->
     < bean id ="profiler" class ="x.y.SimpleProfiler" >
        <!-- execute before the transactional advice (hence the lower order number) -->

         < property name ="order" value ="1" />
     </ bean >

     < tx:annotation-driven transaction-manager ="txManager" />

     < aop:config >
        <!-- this advice will execute around the transactional advice -->
         < aop:aspect id ="profilingAspect" ref ="profiler" >
             < aop:pointcut id ="serviceMethodWithReturnValue" expression ="execution(!void x.y..*Service.*(..))" />
             < aop:around method ="profile" pointcut-ref ="serviceMethodWithReturnValue" />
         </ aop:aspect >
     </ aop:config >

    <!-- other <bean/> definitions such as a DataSource and a PlatformTransactionManager here -->

</ beans >

    1.3.2基于XML Schema
<? 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="
   [url]http://www.springframework.org/schema/beans[/url] [url]http://www.springframework.org/schema/beans/spring-beans-2.0.xsd[/url]
   [url]http://www.springframework.org/schema/tx[/url] [url]http://www.springframework.org/schema/tx/spring-tx-2.0.xsd[/url]
   [url]http://www.springframework.org/schema/aop[/url] [url]http://www.springframework.org/schema/aop/spring-aop-2.0.xsd[/url]" >
    <!-- DefaultFooService的代码跟前面一样,只是没有@Transactional注释-->
     < bean id ="fooService" class ="x.y.service.DefaultFooService" />

    <!-- the profiling advice -->
     < bean id ="profiler" class ="x.y.SimpleProfiler" >
        <!-- execute before the transactional advice (hence the lower order number) -->
         < property name ="order" value ="1" />
     </ bean >

     < aop:config >

         < aop:pointcut id ="entryPointMethod" expression ="execution(* x.y..*Service.*(..))" />

        <!-- will execute after the profiling advice (c.f. the order attribute) -->

         < aop:advisor advice-ref ="txAdvice" pointcut-ref ="entryPointMethod" order ="2" />

        <!-- order value is higher than the profiling aspect -->

         < aop:aspect id ="profilingAspect" ref ="profiler" >
             < aop:pointcut id ="serviceMethodWithReturnValue" expression ="execution(!void x.y..*Service.*(..))" />
             < aop:around method ="profile" pointcut-ref ="serviceMethodWithReturnValue" />
         </ aop:aspect >

     </ aop:config >

     < tx:advice id ="txAdvice" transaction-manager ="txManager" >
         < tx:attributes >
             < tx:method name ="get*" read-only ="true" />
             < tx:method name ="*" />
         </ tx:attributes >
     </ tx:advice >

    <!-- other <bean/> definitions such as a DataSource and a PlatformTransactionManager here -->

</ beans >


1.4Spring1.x版本中声明式事务的配置:
1.4.1配置TransactionProxyFactoryBean
<? xml version ="1.0" encoding ="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
< beans >
     < bean id ="baseTxProxy" lazy-init ="true" class ="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract ="true" >
         < property name ="transactionManager" > < ref bean ="transactionManager" /> </ property >
         < property name ="target" > < ref bean ="daoTarget" /> </ property >
         < property name ="transactionAttributes" >
             < props >
                 < prop key ="*" >PROPAGATION_REQUIRED </ prop >
             </ props >
         </ property >
     </ bean >
    <!-- other <bean/> definitions such as a DataSource and a PlatformTransactionManager here -->
</ beans >

1.4.2利用bean继承简化事务代理的配置
<? xml version ="1.0" encoding ="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
< beans >
     < bean id ="baseTxProxy" lazy-init ="true" class ="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract ="true" >
         < property name ="transactionManager" > < ref bean ="transactionManager" /> </ property >
         < property name ="transactionAttributes" >
             < props >
                     < prop key ="do*" >PROPAGATION_REQUIRED </ prop >
                     < prop key ="get*" >PROPAGATION_REQUIRED </ prop >
                     < prop key ="find*" >PROPAGATION_REQUIRED </ prop >
                     < prop key ="load*" >PROPAGATION_REQUIRED </ prop >
                     < prop key ="update*" >PROPAGATION_REQUIRED </ prop >
                     < prop key ="store*" >PROPAGATION_REQUIRED </ prop >
                     < prop key ="save*" >PROPAGATION_REQUIRED </ prop >
                     < prop key ="delete*" >PROPAGATION_REQUIRED </ prop >
                     < prop key ="print*" >PROPAGATION_REQUIRED </ prop >
             </ props >
         </ property >
     </ bean >
     < bean id ="testTrans1" parent ="baseTxProxy" >
         < property name ="target" >
             < bean class ="x.y.Test1" />
         </ property >
     </ bean >
     < bean id ="testTrans2" parent ="baseTxProxy" >
         < property name ="target" >
             < bean class ="x.y.Test2" />
         </ property >
     </ bean >

    <!-- other <bean/> definitions such as a DataSource and a PlatformTransactionManager here -->
</ beans >

1.4.3根据BeanName自动创建事务代理
<? xml version ="1.0" encoding ="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
< beans >
    <!-- 定义BeanNameAutoProxyCreator-->
     < bean class ="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" >
    <!--   指定对满足哪些bean name的bean自动生成业务代理 -->
         < property name ="beanNames" >
            <!--   下面是所有需要自动创建事务代理的bean-->
             < list >
                 < value >test1 </ value >
                 < value >test2 </ value >
             </ list >
            <!--   此处可增加其他需要自动创建事务代理的bean-->
         </ property >
        <!--   下面定义BeanNameAutoProxyCreator所需的事务拦截器-->
         < property name ="interceptorNames" >
             < list >
                 < value >transactionInterceptor </ value >
                    <!-- 此处可增加其他新的Interceptor -->
             </ list >
         </ property >
     </ bean >
     < bean id ="transactionInterceptor" class ="org.springframework.transaction.interceptor.TransactionInterceptor" >
    <!--   事务拦截器bean需要依赖注入一个事务管理器 -->
     < property name ="transactionManager" ref ="transactionManager" />
     < property name ="transactionAttributes" >
        <!--   下面定义事务传播属性-->
         < props >
             < prop key ="insert*" >PROPAGATION_REQUIRED </ prop >
             < prop key ="find*" >PROPAGATION_REQUIRED,readOnly </ prop >
             < prop key ="*" >PROPAGATION_REQUIRED </ prop >
         </ props >
     </ property >
     </ bean >
    <!-- other <bean/> definitions such as a DataSource and a PlatformTransactionManager here -->
</ beans >



2.编程式事务管理
    不建议使用,略。

3.PlatformTransactionManager
使用Spring时,无论你选择编程式还是声明式的事务管理,定义一个正确的 PlatformTransactionManager 实现都是至关重要的。
一般来说,选择PlatformTransactionManager实现时需要知道当前的工作环境,如JDBC、JTA、Hibernate等。

JDBC:
< 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 >
< bean id ="txManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
   < property name ="dataSource" ref ="dataSource" />
</ bean >


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="
       [url]http://www.springframework.org/schema/beans[/url] [url]http://www.springframework.org/schema/beans/spring-beans-2.0.xsd[/url]
       [url]http://www.springframework.org/schema/jee[/url] [url]http://www.springframework.org/schema/jee/spring-jee-2.0.xsd[/url]" >

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

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

  <!-- other <bean/> definitions here -->

</ beans >

Hibernate局部事务:
< 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 >
< 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全局事务:
<? 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="
       [url]http://www.springframework.org/schema/beans[/url] [url]http://www.springframework.org/schema/beans/spring-beans-2.0.xsd[/url]
       [url]http://www.springframework.org/schema/jee[/url] [url]http://www.springframework.org/schema/jee/spring-jee-2.0.xsd[/url]" >

   < jee:jndi-lookup id ="dataSource" jndi-name ="jdbc/jpetstore" />
   < 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.transaction.jta.JtaTransactionManager" />

  <!-- other <bean/> definitions here -->

</ beans >

你可能感兴趣的:(spring,职场,休闲,手册,简明)