• 当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务汇总运行。
  • 事务的传播行为可以由传播属性指定。Spring定义了7种类传播行为

Sping支持的事务传播行为

传播属性 描述
REQUIRED 如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行。
REQUIRED_NEW 当前的方法必须启动新事务,并在它自己的事务内运行。如果有事务正在运行,应该将它挂起。
SUPPORTS 如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中
NOT_SUPPORTED 当前的方法不应该运行在事务中,如果有运行的事务,将它挂起
MANDATORY 当前的方法必须运行在事务内部,如果没有正在运行的事务,就抛出异常。
NEVER 当前的方法不应该运行在事务中。如果有运行的事务,则抛出异常。
NESTED 如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行。否则,就启动一个新的事务,并在它自己的事务内运行。

spring_(24)Spring_事务传播属性

REQUIRED 传播行为

  • 当bookService的purchase()方法被另一个事务方法checkout()调用时,它默认会在现有的事务内运行。这个默认的传播行为就是REQUIRED。因此在checkout()方法的开始和终止边界内只有一个事务。这个事务只在checkout()方法结束的时候被提交,结果用户一本书都买不了
  • 事务传播属性可以在@Transactional注解的propagation属性中定义

spring_(24)Spring_事务传播属性

REQUIRES_NEW 传播行为(实现买成功一本,第二本依然失败)

  • 另一种常见的传播行为是REQUIRES_NEW.它表示该方法必须启动一个新事务,并在自己的事务内运行。如果有事务在运行,就应该先挂起它。

spring_(24)Spring_事务传播属性

例子程序

这里只贴出有差别的类,其他需要的文件均在上一篇博客

Cashier.java

package com.spring.tx;

import java.util.List;

public interface Cashier {

    public void checkout(String username,List<String> isbns);

}

CashierImpl.java

package com.spring.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service("cashier")
public class CashierImpl implements Cashier{

    @Autowired
    private BookShopService bookShopService;


    @Override
    public void checkout(String username, List<String> isbns) {
        for(String isbn : isbns ){
            bookShopService.purchase(username,isbn);
        }
    }
}

BookShopServiceImpl.java

package com.spring.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService{

    @Autowired
    private BookShopDao bookShopDao;

    //添加事务注解
    //使用propagation 指定事务的传播行为,即当前的事务方法被另外一个事务方法调用时
    //如何使用事务,默认取值为REQUIRED,即使用调用方法的事务
    //REQUIRES_NEW:事务自己的事务,调用的事务方法的事务被挂起
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void purchase(String username, String isbn) {
        //1.获取书的单价
        int price = bookShopDao.findBookPriceByIsbn(isbn);

        //2.更新书的库存
        bookShopDao.updateBookStock(isbn);

        //3.更新用户的余额
        bookShopDao.updateUserAccount(username,price);
    }
}

SpringTransactionTest.java

package com.spring.tx;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Arrays;

public class SpringTransactionTest {

    private ApplicationContext ctx = null;
    private BookShopDao bookShopDao = null;
    private BookShopService bookShopService = null;
    private Cashier cashier = null;

    {
        ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        bookShopDao = ctx.getBean(BookShopDao.class);
        bookShopService = ctx.getBean(BookShopService.class);
        cashier = ctx.getBean(Cashier.class);
    }

    public void testTransactionlPropagation(){
        cashier.checkout("AA",Arrays.asList("1001","1002"));
    }


    public void testBookShopService(){
        bookShopService.purchase("AA","1001");
    }

    public  void testBookShopDaoFindPriceByIsbn(){
        System.out.println(bookShopDao.findBookPriceByIsbn("1001"));
    }

    public void testBookShopDaoUpdateUserAccount(){
        bookShopDao.updateUserAccount("AA",200);
    }

    public void testBookShopDaoUpdateBookStock(){
        bookShopDao.updateBookStock("1001");
    }


    public static void main(String[] args){

        /*new SpringTransactionTest().testBookShopDaoFindPriceByIsbn();
        new SpringTransactionTest().testBookShopDaoUpdateBookStock();
        new SpringTransactionTest().testBookShopDaoUpdateUserAccount();*/

        //
        new SpringTransactionTest().testTransactionlPropagation();

    }

}

简单的补充:

这样的事务使得若买两本书的时候,钱不够,但是依然能够完成支付一本书,第二本书支付失败的情况。

而上一篇博客的情况,则会两本书都不能支付成功。

相关文章: