• SPRING事务_2


    参照资料:Spring资料  http://www.cnblogs.com/charles999/p/6699113.html

     上篇:Spring事务_1

    jdbc.properties 文件的配置

    ----------------------------

    Spring支持两种方式事务管理

    -编程式事务管理

      ·实际应用中很少使用

      ·通过TransactionTemplate手动管理事务

    -使用XML配置声明式事务管理

      ·开发中推荐使用(代码侵入性最小)

      ·Spring的声明式事务是通过AOP实现的

    ---转账环境搭建(http://www.imooc.com/video/9330)--------------------------------------------------------

    创建数据表account
    CREATE TABLE `account` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(20) NOT NULL,
      `money` double DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
    INSERT INTO `account` VALUES ('1', 'aaa', '1000');
    INSERT INTO `account` VALUES ('2', 'bbb', '1000');
    INSERT INTO `account` VALUES ('3', 'ccc', '1000');

    ----interface define-------------------------------------------------------

    AccountDao

    AccountService

    ----interface implement-------------------------------------------------------

    项目实例:银行转账
    第一步:AccountDao.java AccountDaoImpl.java

    public interface AccountDao {
      public void outMoney(String out,Double money);
      public void inMoney(String in,Double money);
    }

       AccountDaoImpl.java

    public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
      public void outMoney(String out,Double money) {
        String sql="update account set money=money-? where name=?";
        this.getJdbcTemplate().update(sql, money, out);
      }  
      public void inMoney(String in,Double money) {
        String sql="update account set money=money+? where name=?";
        this.getJdbcTemplate().update(sql, money, in);
      }  
    }


    第二步:AccountService.java AccountServiceImpl.java

    public interface AccountService {
        public void tranfer(String out,String in,Double money);
    }

     以下蓝色字为匿名内部类

    transactionTemplate.execute(new TransactionCallbackWithoutResult() { //如果匿名内部类要拿到外层包裹它的方法的参数,那么要将final修饰成final
          @Override       

          protected void doInTransactionWithoutResult(TransactionStatus arg0) { // TODO Auto-generated method stub
            accountDao.outMoney(out, money);

            int i=1/0;//发生异常

            accountDao.inMoney(in, money);

          }

    });

    public class AccountServiceImpl implements AccountService {
      //注入DAO类
      private AccountDao accountDao;
    
      public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
      }
      //注入事务管理的模板
      private TransactionTemplate transactionTemplate;
    
      public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
      }
      public void tranfer(final String out,final String in,final Double money) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() { //如果匿名内部类要拿到外层包裹它的方法的参数,那么要将final修饰成final
          @Override 
          protected void doInTransactionWithoutResult(TransactionStatus arg0) {
            // TODO Auto-generated method stub
            accountDao.outMoney(out, money);
            int i=1/0;//发生异常
            accountDao.inMoney(in, money);
          }
        }); 
      }
    }

    第三步:xml

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans
     3 xmlns="http://www.springframework.org/schema/beans"
     4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     5 xmlns:aop="http://www.springframework.org/schema/aop"
     6 xmlns:p="http://www.springframework.org/schema/p"
     7 xmlns:context="http://www.springframework.org/schema/context"
     8 xsi:schemaLocation="http://www.springframework.org/schema/beans 
     9 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    10 http://www.springframework.org/schema/context
    11 http://www.springframework.org/schema/context/spring-context-3.0.xsd
    12 http://www.springframework.org/schema/aop
    13 http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> 
    14 <!-- 引入外部的属性文件 -->
    15 <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    16 <!-- 配置连接池 -->
    17 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    18 <property name="driverClass" value="${jdbc.driverClass}"></property>
    19 <property name="jdbcUrl" value="${jdbc.url}"></property>
    20 <property name="user" value="${jdbc.username}"></property>
    21 <property name="password" value="${jdbc.password}"></property>
    22 </bean>
    23 
    24 <!-- 配置业务层 -->
    25 <bean id="accountService" class="com.imooc.demo1.AccountServiceImpl">
    26 <property name="accountDao" ref="accountDao"></property>
    27 <!-- 注入事务管理的模板 -->
    28 <property name="transactionTemplate" ref="transactionTemplate"></property>
    29 </bean>
    30 <!-- 配置DAO层 -->
    31 <bean id="accountDao" class="com.imooc.demo1.AccountDaoImpl">
    32 <property name="dataSource" ref="dataSource"></property> 
    33 </bean> 
    34 
    35 <!-- 配置事务管理器 -->
    36 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    37 <property name="dataSource" ref="dataSource"></property>
    38 </bean>
    39 
    40 <!-- 配置事务管理的模板:Spring为了简化事务管理的代码而提供的类 -->
    41 <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
    42 <property name="transactionManager" ref="transactionManager"></property>
    43 </bean>
    44 
    45 </beans>

    27-29 注入事务管理的模板(通过set方法注入)

    35-38 配置事务管理器

    40-43 配置事务管理的模板:Spring为了简化事务管理的代码而提供的类

    测试类:第三步没有配置事务管理时(27-29 35-38 40-43)

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContestConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    /**
    *转账测试类
    */
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext2.xml")
    public class SpringDemo1 {
        //注解注入
        @Resource(name="accountService") 
        private AccountService accountService;
    
        @Test
        public void demo1(){
            accountService.tranfer("aaa", "bbb", 200);
        }
    }

    错误信息:

    2017-06-22 11:15:00,866 [main] DEBUG [org.springframework.transaction.support.TransactionTemplate] - Initiating transaction rollback on application exception
    java.lang.ArithmeticException: / by zero
    	at com.imooc.transaction.AccountServiceImpl$1.doInTransactionWithoutResult(AccountServiceImpl.java:30)
    	at org.springframework.transaction.support.TransactionCallbackWithoutResult.doInTransaction(TransactionCallbackWithoutResult.java:34)
    	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
    	at com.imooc.transaction.AccountServiceImpl.transfer(AccountServiceImpl.java:26)
    	at com.imooc.test.TestTransaction.testAspect(TestTransaction.java:22)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:233)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87)
    	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    	at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:176)
    	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
    2017-06-22 11:15:00,867 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Initiating transaction rollback
    2017-06-22 11:15:00,868 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Rolling back JDBC transaction on Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@662ac478]
    2017-06-22 11:15:00,936 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Releasing JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@662ac478] after transaction
    2017-06-22 11:15:00,936 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Returning JDBC Connection to DataSource
    2017-06-22 11:15:00,937 [main] DEBUG [com.mchange.v2.resourcepool.BasicResourcePool] - trace com.mchange.v2.resourcepool.BasicResourcePool@7dcf94f8 [managed: 3, unused: 2, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@248c3047)
    2017-06-22 11:15:00,938 [main] DEBUG [org.springframework.test.context.support.DirtiesContextTestExecutionListener] - After test method: context [DefaultTestContext@256216b3 testClass = TestTransaction, testInstance = com.imooc.test.TestTransaction@2a18f23c, testMethod = testAspect@TestTransaction, testException = java.lang.ArithmeticException: / by zero, mergedContextConfiguration = [MergedContextConfiguration@d7b1517 testClass = TestTransaction, locations = '{classpath:spring-transaction.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], class dirties context [false], class mode [null], method dirties context [false].
    2017-06-22 11:15:00,941 [main] DEBUG [org.springframework.test.context.support.DirtiesContextTestExecutionListener] - After test class: context [DefaultTestContext@256216b3 testClass = TestTransaction, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration@d7b1517 testClass = TestTransaction, locations = '{classpath:spring-transaction.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], dirtiesContext [false].
    2017-06-22 11:15:00,942 [Thread-1] INFO  [org.springframework.context.support.GenericApplicationContext] - Closing org.springframework.context.support.GenericApplicationContext@7a79be86: startup date [Thu Jun 22 11:14:59 CST 2017]; root of context hierarchy
    2017-06-22 11:15:00,943 [Thread-1] DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'lifecycleProcessor'
    2017-06-22 11:15:00,945 [Thread-1] DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@10a035a0: defining beans [org.springframework.context.support.PropertySourcesPlaceholderConfigurer#0,dataSource,accountService,accountDao,transactionManager,transactionTemplate,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor]; root of factory hierarchy
    2017-06-22 11:15:00,945 [Thread-1] DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Retrieved dependent beans for bean 'accountService': [com.imooc.test.TestTransaction]


    ---6-1 Spring声明式编程:使用XML (原始方式)-----------------------------------------------------------------
    Spring声明式编程:使用XML (原始方式)

    1 引入包(以AOP形式开发,AOP传统开发需要以下两个包)

    2 com.springsource.org.aopalliance-1.0.0.jar  AOP联盟包

    spring-aop-3.2.0.RELEASE.jar  AOP包

    配置:

    1 <!-- 配置事务管理器 --> 配置dateSource属性
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource"></property>
    </bean>

    2 <!-- 配置业务层的管理 --> //对目标进行增强
    <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
      <!-- 配置目标对象 -->
      <property name="target" ref="accountService"></property>
      <!-- 注入事务管理器 -->
      <property name="transactionManager" ref="transactionManager"></property>
      <!-- 注入事务属性 -->
      <property name="transactionAttributes">
        <props>
          <!-- prop的格式:

            * PROPAGATION:事务的传播行为

            * ISOLATION  :事务的隔离级别

            * readOnly  : 只读

            * -Exception 发生哪些异常回滚事务

            * +Exception 发生哪些异常事务不回滚

          -->

          //类里的方法,tranfer方法。("*"代表所有方法,此处也可用,因为只有tranfer一个方法)
          <prop key="tranfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop>
        </props>
      </property>
    </bean>
    第一步:

    <?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> 
    <!-- 引入外部的属性文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    <!-- 配置连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
      <property name="driverClass" value="${jdbc.driverClass}"></property>
      <property name="jdbcUrl" value="${jdbc.url}"></property>
      <property name="user" value="${jdbc.username}"></property>
      <property name="password" value="${jdbc.password}"></property>
    </bean>
    
    <!-- 配置业务层 -->
    <bean id="accountService" class="com.imooc.demo2.AccountServiceImpl">
      <property name="accountDao" ref="accountDao"></property>
    </bean>
    <!-- 配置DAO层 -->
    <bean id="accountDao" class="com.imooc.demo2.AccountDaoImpl">
      <property name="dataSource" ref="dataSource"></property> 
    </bean> 
    
    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!-- 配置业务层的管理 -->
    <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
      <!-- 配置目标对象 -->
      <property name="target" ref="accountService"></property>
      <!-- 注入事务管理器 -->
      <property name="transactionManager" ref="transactionManager"></property>
      <!-- 注入事务属性 -->
      <property name="transactionAttributes">
        <props>
          <!-- 
          prop的格式:
          * PROPAGATION 事务的传播行为
          * ISOLATION 事务的隔离级别
          * readOnly 只读(不可更新,插入和删除)
          * -Exception 发生哪些异常回滚事务
          * +Exception 发生哪些异常事务不回滚(,+java.lang.ArithmeticException 就是1/0的异常,此时发生也正常处理)
          -->
          <prop key="tranfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop>
        </props>
      </property>
    </bean>
    </beans>
    service类
    public class AccountServiceImpl implements AccountService {
      //注入DAO类
      private AccountDao accountDao;
    
      public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
      }
    
      public void tranfer(final String out,final String in,final Double money) {
        accountDao.outMoney(out, money);
        int i=1/0;//发生异常
        accountDao.inMoney(in, money);
      }
    }


    第二步:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext2.xml")
    public class Demo2Test {
      //配置 注入代理类(代理类被增强了) accountServiceProxy
      //@Resource(name="accountService")
         @Resource(name="accountServiceProxy") 
      private AccountService accountService;
    
      @Test
      public void demo2(){
        accountService.tranfer("aaa", "bbb", 200d);
      }
    }

    ---6-2 声明式事务管理方式二:基于AspectJ的XML方式----------------------------------------------------------------------

    Spring声明式编程:使用XML(AspectJ方式)

    JAR包:

    com.springsource.org.aspectj.weaver-1.6.8.RELEASE

    spring-aspects-3.2.0.RELEASE
    第一步

    引入约束:
    <beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:context="http://www.springframework.org/schema/context"

    xmlns:aop="http://www.springframework.org/schema/aop"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xmlns:task="http://www.springframework.org/schema/task"

    xsi:schemaLocation="http://www.springframework.org/schema/beans    

        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd

        http://www.springframework.org/schema/context

        http://www.springframework.org/schema/context/spring-context-3.1.xsd

        http://www.springframework.org/schema/aop

        http://www.springframework.org/schema/aop/spring-aop-3.1.xsd

        http://www.springframework.org/schema/tx

        http://www.springframework.org/schema/tx/spring-tx-3.1.xsd

        http://www.springframework.org/schema/task

        http://www.springframework.org/schema/task/spring-task-3.1.xsd">

    <?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:context="http://www.springframework.org/schema/context"
         xmlns:aop="http://www.springframework.org/schema/aop"
         xmlns:tx="http://www.springframework.org/schema/tx"
         xmlns:task="http://www.springframework.org/schema/task"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
             http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context-3.1.xsd
             http://www.springframework.org/schema/aop
             http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
             http://www.springframework.org/schema/tx
             http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
             http://www.springframework.org/schema/task
             http://www.springframework.org/schema/task/spring-task-3.1.xsd">
    
        <!-- 引入外部的属性文件 -->
        <context:property-placeholder location="classpath:jdbc.properties"/>
        
        <!-- 配置c3p0连接池 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${jdbc.driverClass}" />
            <property name="jdbcUrl" value="${jdbc.url}" />
            <property name="user" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
        </bean>
        
        <!-- 配置业务层类 -->
        <bean id="accountService" class="com.zs.spring.demo3.AccountServiceImpl">
            <property name="accountDao" ref="accountDao" />
        </bean>
        
        <!-- 配置DAO类(简化,会自动配置JdbcTemplate) -->
        <bean id="accountDao" class="com.zs.spring.demo3.AccountDaoImpl">
            <property name="dataSource" ref="dataSource" />
        </bean>
        
        <!-- ==================================3.使用XML配置声明式的事务管理,基于tx/aop=============================================== -->
        
        <!-- 配置事务管理器 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
        </bean>
        
        <!-- 配置事务的通知 -->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <!-- 
                    propagation    :事务传播行为
                    isolation    :事务的隔离级别
                    read-only    :只读
                    rollback-for:发生哪些异常回滚
                    no-rollback-for    :发生哪些异常不回滚
                    timeout        :过期信息
                 -->
                <tx:method name="transfer" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
        
        <!-- 配置切面 -->
        <aop:config>
            <!-- 配置切入点 -->
            <aop:pointcut expression="execution(* com.zs.spring.demo3.AccountService+.*(..))" id="pointcut1"/>
            <!-- 配置切面 -->
            <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
        </aop:config>
    
    </beans>

    *代表方法返回值(*为任意返回值) 

    +代表子类

    <aop:pointcut expression="execution(* com.zs.spring.demo3.AccountService+.*(..))" id="pointcut1"/>

    advisor:一个切入点一个通知时使用(aspect多个切入点和多个通知时使用)

    <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>

        <!-- 配置事务的通知 -->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <!-- propagation :事务传播行为

          isolation :事务的隔离级别

          read-only :只读

          rollback-for:发生哪些异常回滚

          no-rollback-for :发生哪些异常不回滚

          timeout :过期信息 -->
                <tx:method name="transfer" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>

         <!-- 配置切面 -->
        <aop:config>
            <!-- 配置切入点 -->
            <aop:pointcut expression="execution(* com.zs.spring.demo3.AccountService+.*(..))" id="pointcut1"/>
            <!-- 配置切面 :在"pointcut1"切入点上用"txAdvice"增强-->
            <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
        </aop:config>


    第二步:测试类
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext3.xml")
    public class Demo3Test {
      @Resource(name="accountService")
      private AccountService accountService;

      @Test
      public void demo3(){
        accountService.tranfer("aaa", "bbb", -200d);
      }
    }

    ----6-3 Spring声明式编程:使用XML(注解方式)-----------------------------------------------------------------------------------------------
    Spring声明式编程:使用XML(注解方式)
    第一步:

    1. 配置事务管理器
    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <!-- 注入连接池 -->
      <property name="dataSource" ref="dataSource"></property>
    </bean>
    2. 开启注解事务
    <!-- 开启注解事务 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    3.在业务层添加注解

    /*
    * @Transactional注解属性: *
    * propagation:事务传播行为
    isolation:事务隔离级别
    readOnly:只读
    rollBbackFor:发生哪些异常回滚
    noRollbackFor:发生哪些异常不回滚
    */

    @Transactional//不添加注解property时,采用默认值
    //@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,readOnly=false) 可添加注解property
    public class AccountServiceImpl implements AccountService {

    <?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:context="http://www.springframework.org/schema/context"
         xmlns:aop="http://www.springframework.org/schema/aop"
         xmlns:tx="http://www.springframework.org/schema/tx"
         xmlns:task="http://www.springframework.org/schema/task"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
             http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context-3.1.xsd
             http://www.springframework.org/schema/aop
             http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
             http://www.springframework.org/schema/tx
             http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
             http://www.springframework.org/schema/task
             http://www.springframework.org/schema/task/spring-task-3.1.xsd">
    
        <!-- 引入外部的属性文件 -->
        <context:property-placeholder location="classpath:jdbc.properties"/>
        
        <!-- 配置c3p0连接池 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${jdbc.driverClass}" />
            <property name="jdbcUrl" value="${jdbc.url}" />
            <property name="user" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
        </bean>
        
        <!-- 配置业务层类 -->
        <bean id="accountService" class="com.zs.spring.demo4.AccountServiceImpl">
            <property name="accountDao" ref="accountDao" />
        </bean>
        
        <!-- 配置DAO类(简化,会自动配置JdbcTemplate) -->
        <bean id="accountDao" class="com.zs.spring.demo4.AccountDaoImpl">
            <property name="dataSource" ref="dataSource" />
        </bean>
        
        <!-- ==================================4.使用注解配置声明式事务============================================ -->
    
        <!-- 配置事务管理器 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
        </bean>
        
        <!-- 开启注解事务 -->
        <tx:annotation-driven transaction-manager="transactionManager"/>
        
    </beans>

    第二步:
    /*
    * @Transactional注解属性: *
    * propagation:事务传播行为
    isolation:事务隔离级别
    readOnly:只读
    rollBbackFor:发生哪些异常回滚
    noRollbackFor:发生哪些异常不回滚
    */
    @Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,readOnly=false)
    public class AccountServiceImpl implements AccountService {

    ---7 事务总结----------------------------------------------------------------

    Spring将事务管理分成了两类:
     1. 编程式事务管理
      手动编写代码进行事务管理.(很少使用)
     2. 声明式事务管理:
      * 基于TransactionProxyFactoryBean的方式.(很少使用)
      * 需要为每个进行事务管理的类,配置一个TransactionProxyFactoryBean进行增强.
      * 基于AspectJ的XML方式.(经常使用)
          1)XML可很清晰的看到那些类配置了事务管理

        2)一旦配置好之后,类上不需要添加任何东西
      * 基于注解方式.(经常使用)
          1) 配置简单,需要在业务层上添加一个@Transactional的注解.
      

    =================================================
    总结:
    Spring的编程式事务管理(事务管理模板)(很少使用)
    1.通过TrasactionTemplate手动管理事务
    2.在AccountService中使用TransactionTemplate
    3.TransactionTemplate依赖DataSourceTransactionManager
    4.DataSourceTransactionManager依赖DataSource构造

    (事务管理器有了连接池才能获得链接进行事务管理)


    Spring的声明式事务管理(通过AOP实现的)
    第一种:基于代理TransactionProxyFactoryBean;
    注入:目标,事务管理器,事务属性:
    1.PROPAGATION :事务的传播行为
    2.ISOLATION :事务的隔离级别
    3.readOnly :只读,(不可以进行修改,插入,删除)
    4.-Exception :发生那些异常回滚事务
    5.+Exception :发生那些异常事务不回滚
    第二种:基于AspectJ的XML方式(aspectJ的话,就是分的更加的详细,切入点(类),切入面(方法))
    1.配置事务的通知<tx>
    2.配置切面,切点<aop>
    第三种:基于注解的方式
    1.开启事务<tx:annotation-driven transaction-Manager="" />
    2.service类@Transactional(name=value)

     ======================================================

    事务的特性:
    事务是一个不可分割的工作单位,所有操作要么全部执行,要么都不执行
    1.原子性: 指的是事物是一个不可分割的部分,要么都发生。要么都不发生
    2.隔离性: 多个并发事物之间数据要相互隔离
    3.一致性: 事物处理前后数据的完整性必须保持一致
    4.持久性: 一个事物被提交之后。它对数据库中数据的改变是持久的

    Spring事务管理接口
    PlatformTransationManager:事务管理器
    TransactionDefinition:事务定义信息(隔离、传播、超时、只读)
    TransactionStatus:事务具体运行状态

    PlatformTransactionManager
    spring为了不同的持久化框架提供了不同的PlatformTransactionManagerPlatgorfTransactionManager的实现类
    org.springframework.jdbc.datasource.DataSourceTransactionManager:使用Spring JDBC或iBatis进行持久化数据时
    org.springframework.orm.hibernate3.HibernateTransactionManager:使用Hibernate3.0版本进行持久化数据时
    org.springframework.orm.jpa.JpaTransactionManager:使用JPA进行持久化时
    org.springframework.orm.jdo.JdoTransactionManager:当持久化机制是Jdo时
    org.springframework.transaction.jta.JtaTransactionManager:使用一个JTA来管理事务,在一个事务跨越越多个资源时必须使用

    七种事务传播路径
    PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
    PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
    PROPAGATION_MANDATORY--该方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果在没有事务的环境下被调用,容器抛出例外。
    PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
    PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
    PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
    PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

    事务隔离级别:
    脏读:一个事务读取了另一个事务改写但未提交的数据,如果这些数据回滚则读到的数据是无效的。
    不可重复读:一个事务读取了另一个事务提交的更新数据
    幻读:一个事务读取了另一个事务插入的数据

    Spring事务的隔离级别
    TransactionDefinition接口的常量中ISOLATION_开头的表示事物的隔离级别
    1. ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别. 另外四个与JDBC的隔离级别相对应
    2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。 这种隔离级别会产生脏读,不可重复读和幻像读。
    3. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
    4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。 它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
    5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。 除了防止脏读,不可重复读外,还避免了幻像读。
    MySQL默认事务隔离级别:REPATABLE_READ(可能出现幻读)
    Oracle默认:READ_COMMITTED(可能出现不可重复读和幻读)

    Spring编程式事务管理
    (1)在AccountService中使用TransactionTemplate
    (2)TransactionTemplate依赖DataSourceTransactionManager
    (3)DataSourceTransactionManager依赖DataSource构造

  • 相关阅读:
    [笔记] 辛普森积分
    Luogu P4175 [CTSC2008]网络管理
    Luogu P4331 [BOI2004]Sequence 数字序列
    Luogu P1456 Monkey King
    Luogu P3261 [JLOI2015]城池攻占
    Luogu P4309 [TJOI2013]最长上升子序列
    Luogu P4246 [SHOI2008]堵塞的交通
    Luogu P3638 [APIO2013]机器人
    Luogu P4294 [WC2008]游览计划
    CF613D Kingdom and its Cities
  • 原文地址:https://www.cnblogs.com/charles999/p/6698819.html
Copyright © 2020-2023  润新知