sprig学习笔记十九 事务的传播行为

这篇在上一篇的基础上,代码基本相同,添加了一个接口cashier,和这个接口的实现类cashierImpl.java,最后在测试类中测试;

问题:当一个人连续买两本书,连续两次调用事务,当余额充足的时候不会抛出异常;但是当余额只够购买一本书时,结果就是一本 没买。我们要求能买多少卖多少。


定义一个接口Cashier.java

package spring.tx;

import java.util.List;

public interface Cashier {

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


实现这个接口CashierImpl.java

username这个人,将会买isbns中的书

package spring.tx;

import java.util.List;

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

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

	@Autowired
	private BookShopService bookShopService=null;
	
	//一次买几本书
	@Transactional
	@Override
	public void checkout(String username, List<String> isbns) {
		for(String isbn:isbns){
			bookShopService.purchase(username, isbn);
		}

	}

}


更改BookShopServiceImpl.java

package 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.updataUserAccount(username, price);
	}

}



测试类SpringTransactionTest.java

注意:测试的时候,只要选中你要测试测试的方法名称,然后右击run as JUnit Test,就测试这个方法了。


package spring.tx;

import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.*;

import java.util.Arrays;

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

import com.mysql.fabric.xmlrpc.base.Array;

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);
	}
	
	@Test
	public void testTransactionlPropagation(){
		cashier.checkout("AA", Arrays.asList("1001","1002"));
	}
	
	//购买商品
	@Test
	public void testBookShopService(){
		bookShopService.purchase("AA", "1001");
	}
	//更新账户
	@Test
	public void testBookShopDaoUpdateUserAccount(){
		bookShopDao.updataUserAccount("AA", 200);
	}
	//根据书号更新书的库存
	@Test
	public void testBookShopDaoUpdateBookStock(){
		bookShopDao.updateBookStock("1001");
	}
	//根据书号查询
	@Test
	public void testBookShopDaoFindPriceByIsbn() {
		System.out.println(bookShopDao.findBookPriceByIsbn("1001"));
	}

}

初始数据库表:

账户余额书的库存

当第一次运行testTransactionlPropagation方法,结果

账户余额书的库存

当第二次运行testTransactionlPropagation方法,结果

首先会抛出异常,然后数据库结果为:


账户余额书的库存



小结:

事务传播属性:当事务方法被另一个事务方法调用时,必须制定事务应该如何传播。例如:方法可能继续在现有的事务中运行,也可能开启另一个新事务,并在自己的事务中运行。
    事务的传播行为可以有传播属性指定,spring定义了7种传播行为。
    
      Require:支持当前事务,如果没有事务,就建一个新的,这是最常见的;


  Supports:支持当前事务,如果当前没有事务,就以非事务方式执行;


  Mandatory:支持当前事务,如果当前没有事务,就抛出异常;


  RequiresNew:新建事务,如果当前存在事务,把当前事务挂起;


  NotSupported:以非事务方式执行操作,如果当前存在事务,就把事务挂起;


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


  Nested:新建事务,如果当前存在事务,把当前事务挂起。与RequireNew的区别是与父事务相关,且有一个savepoint。


  其中,Require、Supports、NotSupported、Never两个看文字也就能了解,就不多说了。而Mandatory是要求所有的操作必须在一个事务里,较Require来说,对事务要求的更加严格。


  RequireNew:当一个Require方法A调用RequireNew方法B时,B方法会新new一个事务,并且这个事务和A事务没有关系,也就是说B方法出现异常,不会导致A的回滚,同理当B已提交,A再出现异常,B也不会回滚。


  Nested:这个和RequireNew的区别是B方法的事务和A方法的事务是相关的。只有在A事务提交的时候,B事务都会提交。也就是说当A发生异常时,A、B事务都回滚,而当B出现异常时,B回滚,而A回滚到savepoint,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Spring框架中,事务传播行为用于定义一个方法调用时如何参与到已存在的事务中,或者如何创建一个新的事务。Spring框架提供了多种事务传播行为选项,可以通过@Transactional注解或者编程式事务管理来配置。 以下是一些常见的Spring事务传播行为: 1. REQUIRED(默认):如果当前存在事务,则加入该事务;如果没有事务,则创建一个新的事务。这是最常用的传播行为,适合大多数情况。 2. SUPPORTS:如果当前存在事务,则加入该事务;如果没有事务,则以非事务的方式执行。适用于不需要强制要求事务的场景。 3. MANDATORY:如果当前存在事务,则加入该事务;如果没有事务,则抛出异常。适用于必须在一个已存在的事务中执行的场景。 4. REQUIRES_NEW:创建一个新的事务,并挂起当前的事务(如果存在)。适用于需要独立的事务执行的场景。 5. NOT_SUPPORTED:以非事务的方式执行操作,挂起当前的事务(如果存在)。适用于不需要事务支持的场景。 6. NEVER:以非事务的方式执行操作,如果当前存在事务,则抛出异常。适用于必须在没有事务的环境下执行的场景。 7. NESTED:如果当前存在事务,则在嵌套事务中执行;如果没有事务,则创建一个新的事务。嵌套事务是独立于外部事务的内部事务,它可以独立地进行提交或回滚,但是如果外部事务回滚,嵌套事务也会回滚。 通过选择合适的事务传播行为,可以确保在不同的方法调用中有效地管理事务,保证事务的一致性和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不染心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值