美文网首页程序员
spring事物传播特性

spring事物传播特性

作者: 尉昌达 | 来源:发表于2020-06-21 15:02 被阅读0次

    BookDao.java

    @Repository
    public class BookDao {
    
        @Autowired
        JdbcTemplate jdbcTemplate;
    
        /**
         * 减去某个用户的余额
         * @param userName
         * @param price
         */
        public void updateBalance(String userName,int price){
            String sql = "update account set balance=balance-? where username=?";
            jdbcTemplate.update(sql,price,userName);
        }
    
        /**
         * 按照图书的id来获取图书的价格
         * @param id
         * @return
         */
        public int getPrice(int id){
            String sql = "select price from book where id=?";
            return jdbcTemplate.queryForObject(sql,Integer.class,id);
        }
    
        /**
         * 减库存,减去某本书的库存
         * @param id
         */
        public void updateStock(int id){
            String sql = "update book_stock set stock=stock-1 where id=?";
            jdbcTemplate.update(sql,id);
        }
    
        /**
         * 修改图书价格
         * @param id
         * @param price
         */
        public void updatePrice(int id,int price){
            String sql = "update book set price=? where id =?";
            jdbcTemplate.update(sql,price,id);
        }
    }
    

    BookService.java

    @Service
    public class BookService {
    
        @Autowired
        BookDao bookDao;
    
        /**
         * 结账:传入哪个用户买了哪本书
         * @param username
         * @param id
         */
        @Transactional(propagation = Propagation.REQUIRED)
        public void checkout(String username,int id) {
    
            bookDao.updateStock(id);
            int price = bookDao.getPrice(id);
            bookDao.updateBalance(username,price);
        }
    
        @Transactional(propagation = Propagation.REQUIRED)
        public void updatePrice(int id,int price){
            bookDao.updatePrice(id,price);
            int i = 1/0;
        }
    }
    

    MulService.java

    @Service
    public class MulService {
    
        @Autowired
        private BookService bookService;
    
        @Transactional
        public void mulTx(){
            bookService.checkout("zhangsan",1);
            bookService.updatePrice(1,1000);
        }
    }
    

    MyTest.java

    public class MyTest {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("jdbcTemplate.xml");
            MulService mulService = context.getBean("mulService", MulService.class);
            mulService.mulTx();
        }
    }
    

    通过上图的结果发现,如果设置的传播特性是Required,那么所有的事务都会统一成一个事务,一旦发生错误,所有的数据都要进行回滚。

    BookService.java

    @Service
    public class BookService {
    
        @Autowired
        BookDao bookDao;
    
        /**
         * 结账:传入哪个用户买了哪本书
         * @param username
         * @param id
         */
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void checkout(String username,int id) {
    
            bookDao.updateStock(id);
            int price = bookDao.getPrice(id);
            bookDao.updateBalance(username,price);
        }
    
        @Transactional(propagation = Propagation.REQUIRED)
        public void updatePrice(int id,int price){
            bookDao.updatePrice(id,price);
            int i = 1/0;
        }
    }
    

    通过修改checkout方法的传播特性为Required_new,发现价格进行了回滚,而其他的数据没有进行回滚。

    BookService.java

    @Service
    public class BookService {
    
        @Autowired
        BookDao bookDao;
    
        /**
         * 结账:传入哪个用户买了哪本书
         * @param username
         * @param id
         */
        @Transactional(propagation = Propagation.REQUIRED)
        public void checkout(String username,int id) {
    
            bookDao.updateStock(id);
            int price = bookDao.getPrice(id);
            bookDao.updateBalance(username,price);
        }
    
        @Transactional(propagation = Propagation.REQUIRED)
        public void updatePrice(int id,int price){
            bookDao.updatePrice(id,price);
        }
    }
    

    MulService.java

    @Service
    public class MulService {
    
        @Autowired
        private BookService bookService;
    
        @Transactional
        public void mulTx(){
            bookService.checkout("zhangsan",1);
            bookService.updatePrice(1,1000);
            int i = 1/0;
        }
    }
    

    将bookservice方法的传播行为为Required,并且将报错设置在MulService中,发现会都进行回滚。

    BookService.java

    @Service
    public class BookService {
    
        @Autowired
        BookDao bookDao;
    
        /**
         * 结账:传入哪个用户买了哪本书
         * @param username
         * @param id
         */
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void checkout(String username,int id) {
    
            bookDao.updateStock(id);
            int price = bookDao.getPrice(id);
            bookDao.updateBalance(username,price);
        }
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void updatePrice(int id,int price){
            bookDao.updatePrice(id,price);
        }
    }
    

    MulService.java

    @Service
    public class MulService {
    
        @Autowired
        private BookService bookService;
    
        @Transactional
        public void mulTx(){
            bookService.checkout("zhangsan",1);
            bookService.updatePrice(1,1000);
            int i = 1/0;
        }
    }
    
    

    ​ 将bookservice方法的传播行为为Requires_new,并且将报错设置在MulService中,发现都不会进行回滚。

    BookService.java

    @Service
    public class BookService {
    
        @Autowired
        BookDao bookDao;
    
        /**
         * 结账:传入哪个用户买了哪本书
         * @param username
         * @param id
         */
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void checkout(String username,int id) {
    
            bookDao.updateStock(id);
            int price = bookDao.getPrice(id);
            bookDao.updateBalance(username,price);
        }
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void updatePrice(int id,int price){
            bookDao.updatePrice(id,price);
        }
    
        @Transactional
        public void mulTx(){
            checkout("zhangsan",1);
            updatePrice(1,1000);
            int i = 1/0;
        }
    }
    

    ​ 如果在bookservice执行的话,会发现刚刚的效果就没有了,原因是外层调用的时候使用的AOP,但是本类方法自己的调用就是最最普通的调用,就是同一个事务。

    总结:

    1、事务传播级别是REQUIRED,当checkout()被调用时(假定被另一类中commit()调用),如果checkout()中的代码抛出异常,即便被捕获,commit()中的其他代码都会roll back
    2、是REQUIRES_NEW,如果checkout()中的代码抛出异常,并且被捕获,commit()中的其他代码不会roll back;如果commit()中的其他代码抛出异常,而且没有捕获,不会导致checkout()回滚
    3、是NESTED,如果checkout()中的代码抛出异常,并且被捕获,commit()中的其他代码不会roll back;如果commit()中的其他代码抛出异常,而且没有捕获,会导致checkout()回滚

    4.PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行.

    5.另一方面, PROPAGATION_NESTED 开始一个 "嵌套的" 事务, 它是已经存在事务的一个真正的子事务. 嵌套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 嵌套事务是外部事务的一部分, 只有外部事务结束后它才会被提交.

    6.由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 嵌套事务也会被 commit, 这个规则同样适用于 roll back.

    基于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:context="http://www.springframework.org/schema/context"
           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.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/aop
           https://www.springframework.org/schema/aop/spring-aop.xsd
           http://www.springframework.org/schema/tx
           https://www.springframework.org/schema/tx/spring-tx.xsd
    ">
        <context:component-scan base-package="com.mashibing"></context:component-scan>
        <context:property-placeholder location="classpath:dbconfig.properties"></context:property-placeholder>
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="username" value="${jdbc.username}"></property>
            <property name="password" value="${jdbc.password}"></property>
            <property name="url" value="${jdbc.url}"></property>
            <property name="driverClassName" value="${jdbc.driverClassName}"></property>
        </bean>
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
        </bean>
        <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
            <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
        </bean>
        <!--事务控制-->
        <!--配置事务管理器的bean-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        <!--
        基于xml配置的事务:依赖tx名称空间和aop名称空间
            1、spring中提供事务管理器(切面),配置这个事务管理器
            2、配置出事务方法
            3、告诉spring哪些方法是事务方法(事务切面按照我们的切入点表达式去切入事务方法)
        -->
        <bean id="bookService" class="com.mashibing.service.BookService"></bean>
        <aop:config>
            <aop:pointcut id="txPoint" expression="execution(* com.mashibing.service.*.*(..))"/>
            <!--事务建议:advice-ref:指向事务管理器的配置-->
            <aop:advisor advice-ref="myAdvice" pointcut-ref="txPoint"></aop:advisor>
        </aop:config>
        <tx:advice id="myAdvice" transaction-manager="transactionManager">
            <!--事务属性-->
            <tx:attributes>
                <!--指明哪些方法是事务方法-->
                <tx:method name="*"/>
                <tx:method name="checkout" propagation="REQUIRED"/>
                <tx:method name="get*" read-only="true"></tx:method>
            </tx:attributes>
        </tx:advice>
    </beans>
    

    相关文章

      网友评论

        本文标题:spring事物传播特性

        本文链接:https://www.haomeiwen.com/subject/esqaxktx.html