zoukankan      html  css  js  c++  java
  • Spring 7种事务传播行为

    1、PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。

    2、PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘

    3、PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。

    4、PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。

    5、PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

    6、PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

    7、PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

    罗列了7种spring的事务传播行为,我们具体来看看它的实现。在这里,我们使用spring annotation注解实现事务。

    实现事务的类BusinessServiceImpl

    package com.aop;
     
    import org.springframework.aop.support.AopUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Isolation;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
     
    import com.entity.Student;
     
    @Service("businessSerivce")
    public class BusinessServiceImpl implements IBaseService {
     
        @Autowired
        IStudentDao studentDao;
     
        @Autowired
        IBaseServiceB baseServiceb;
     
        @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
        public String doA() throws Exception {
            Student st = new Student();
            st.setId(1);
            st.setSex("girl");
            st.setUsername("zx");
            studentDao.insertStudent(st);
     
            System.out.println(baseServiceb);
            System.out.println("是否是代理调用,AopUtils.isAopProxy(baseServiceb) : " + AopUtils.isAopProxy(baseServiceb));
            System.out
                    .println("是否是cglib类代理调用,AopUtils.isCglibProxy(baseServiceb) : " + AopUtils.isCglibProxy(baseServiceb));
            System.out.println("是否是jdk动态接口代理调用,AopUtils.isJdkDynamicProxy(baseServiceb) : "
                    + AopUtils.isJdkDynamicProxy(baseServiceb));
            
            //使用代理调用方法doB()
            baseServiceb.doB();
            int i = 1 / 0;// 抛出异常,doB()的事务事务回滚
            return "success";
        }
     
        // @Transactional(propagation = Propagation.REQUIRES_NEW, isolation =
        // Isolation.DEFAULT, rollbackFor = Exception.class)
        // public String doB() throws Exception {
        // Student st = new Student();
        // st.setId(2);
        // st.setSex("girl");
        // st.setUsername("zx2");
        // studentDao.insertStudent(st);
        //
        // return "success";
        // }
     
    }

    实现事务的类BusinessServiceImpl

    package com.aop;
     
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Isolation;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
     
    import com.entity.Student;
     
    @Service("businessSerivceB")
    public class BusinessServiceImplB implements IBaseServiceB {
      
        @Autowired
        IStudentDao studentDao;
        
        @Transactional(propagation = Propagation.REQUIRES_NEW,isolation=Isolation.DEFAULT,rollbackFor=Exception.class)  
        public String doB() throws Exception {
            Student st = new Student();
            st.setId(2);
            st.setSex("girl");
            st.setUsername("zx2");
            studentDao.insertStudent(st);
            return "success";
        }
         
    }

    测试类:

    package com.aop;
     
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
     
    import com.thread.service.IBaseFacadeService;
     
     
    //@RunWith(SpringJUnit4ClassRunner.class)
    //@ContextConfiguration(locations = { "classpath:/spring-ibatis.xml", "classpath:/spring-jdbctemplate.xml" })
    public class TestStudentDao {
     
        public static void main(String[] args) {
              try {
              BeanFactory factory = new ClassPathXmlApplicationContext("spring-jdbctemplate.xml");
              IBaseService service = (IBaseService) factory.getBean("businessSerivce");
            
                  service.doA();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    测试结果:

    om.aop.BusinessServiceImplB@14b75fd9
    是否是代理调用,AopUtils.isAopProxy(baseServiceb) : true
    是否是cglib类代理调用,AopUtils.isCglibProxy(baseServiceb) : true
    是否是jdk动态接口代理调用,AopUtils.isJdkDynamicProxy(baseServiceb) : false
    java.lang.ArithmeticException: / by zero

    从测试结果可以看到,我们在数据库中成功插入了doB()方法中要插入的数据,而doA()中插入的数据被回滚了,这是因为我们在doB()方法中加入ROPAGATION_REQUIRES_NEW传播行为,doB()创建了属于自己的事务,挂起了doA()中的事务,所以事务B提交了,而事务A因为执行异常插入的数据被回滚了。

    如果我们将BusinessServiceImplB做下修改,改为第一种传播行为ROPAGATION_REQUIRED

    package com.aop;
     
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Isolation;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
     
    import com.entity.Student;
     
    @Service("businessSerivceB")
    public class BusinessServiceImplB implements IBaseServiceB {
      
        @Autowired
        IStudentDao studentDao;
        
        @Transactional(propagation = Propagation.REQUIRED,isolation=Isolation.DEFAULT,rollbackFor=Exception.class)  
        public String doB() throws Exception {
            Student st = new Student();
            st.setId(2);
            st.setSex("girl");
            st.setUsername("zx2");
            studentDao.insertStudent(st);
            return "success";
        }
         
    }

    测试结果:

    com.aop.BusinessServiceImplB@97c87a4
    是否是代理调用,AopUtils.isAopProxy(baseServiceb) : true
    是否是cglib类代理调用,AopUtils.isCglibProxy(baseServiceb) : true
    是否是jdk动态接口代理调用,AopUtils.isJdkDynamicProxy(baseServiceb) : false
    java.lang.ArithmeticException: / by zero

    从结果可以看到,我们没有成功插入数据,这是为什么呢?因为我们使用的是第一种传播行为PROPAGATION_REQUIRED ,doB()方法被加入到doA()的事务中,doA()执行时抛出了异常,因为doB()和doA()同属于一个事务,则执行操作被一起回滚了。其实在doB()中我们不加入注解,也等同PROPAGATION_REQUIRED的效果。

    接下来我们再来看看第五种传播行为PROPAGATION_NOT_SUPPORTED,我们同样修改B类,如下

    package com.aop;
     
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Isolation;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
     
    import com.entity.Student;
     
    @Service("businessSerivceB")
    public class BusinessServiceImplB implements IBaseServiceB {
      
        @Autowired
        IStudentDao studentDao;
        
        @Transactional(propagation = Propagation.NOT_SUPPORTED,isolation=Isolation.DEFAULT,rollbackFor=Exception.class)  
        public String doB() throws Exception {
            Student st = new Student();
            st.setId(2);
            st.setSex("girl");
            st.setUsername("zx2");
            studentDao.insertStudent(st);
            return "success";
        }
         
    }

    测试结果:


    可以看到doB()方法成功插入了数据。doA()方法中插入的数据被回滚了。这是因为传播行为PROPAGATION_NOT_SUPPORTED是doB()以非事务执行的,并且提交了。所以当doA()的事务被回滚时,doB()的操作没有被回滚。

    其他的传播行为就不一一列举了,机制是差不多的。

    注意:在上面的实例中,我没有把doB()方法放在类BusinessServiceImpl,而是放在BusinessServiceImplB中,这是因为spring通过扫描所有含有注解的@Trasation的方法,使用aop形成事务增强advise。但是加入增强时是通过代理对象调用方法的形式加入的,如果将doB()方法放在doA()方法直接调用时,在调用doB()方法的时候是通过当前对象来调用doB()方法的,而不是通过代理来调用的doB()方法,这个时候doB()方法上加的事务注解就失效了不起作用。在Spring事务传播行为在内部方法不起作用讲到。

    spring配置文件:

    <?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:p="http://www.springframework.org/schema/p"
        xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop"
        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
                http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd"
                default-lazy-init="false">
     
        <context:component-scan base-package="com.aop"/>
        <aop:aspectj-autoproxy proxy-target-class="true"/>
        <!-- 数据 -->
        <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/lpWeb"/>
            <property name="username" value="root"/>
            <property name="password" value="root123"/>
        </bean>
        
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
             <property name = "dataSource" ref="dataSource"/>  
        </bean>
      
         <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean> 
        
        <tx:annotation-driven transaction-manager="transactionManager" />  
    </beans>
  • 相关阅读:
    Android 编程下 Eclipse 恢复被删除的文件
    Android 编程下背景图片适配工具类
    Android 编程下 Managing Your App's Memory
    Android 编程下代码之(QQ消息列表滑动删除)
    Android 编程下 Canvas and Drawables
    Android 编程下 AlarmManager
    Android 编程下去除 ListView 上下边界蓝色或黄色阴影
    Java 编程下字符串的 16 位、32位 MD5 加密
    C#枚举类型和int类型相互转换
    MVC和普通三层架构的区别
  • 原文地址:https://www.cnblogs.com/jtlgb/p/9480005.html
Copyright © 2011-2022 走看看