笔记:Spring之常用数据库事务传播属性和事务的隔离级别

Spring事务传递

  • 传播属性
    • 什么是事务传播属性
    • Spring定义的7种类传播行为
    • 实现
      • 1. REQUIRED
      • 2. REQUIRES_NEW
      • 3. 其他几种同理
  • **事务的隔离级别**
    • **数据库事务并发问题**
      • **脏读**
      • **不可重复读**
      • **幻读**
    • 事物隔离级别
      • 读未提交 Isolation.READ_UNCOMMITTED
      • 读已提交 Isolation.READ_COMMITTED
      • 可重复读: Isolation.REPEATABLE_READ
      • 串行化 Isolation.SERIALIZABLE
    • 各个隔离级别解决并发问题的能力
    • 各种数据库产品对事务隔离级别的支持程度

传播属性

什么是事务传播属性

  • 当事务方法被另一个事务方法调用时,必须制定事务应该如何传播
    • 例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中娙。
  • 一个方法运行在了一个开启了事务的方法中时,当前方法是使用原来的事务还是开启一个新的事务

Spring定义的7种类传播行为

事务的传播行为可以由传播属性指定

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

实现

  • 注解方式(声明式事务)
  • 部分代码
@Service("cashier")
public class CashierImpl implements Cashier {

	@Autowired
	private BookShopService bookShopService;
	
	@Transactional
	@Override
	public void checkout(int userId, List<String> isbns) {
		for (String isbn : isbns) {
			//调用BookShopService中买东西的方法
			bookShopService.purchase(userId, isbn);
		}
	}

}

@Transactional(propagation= Propagation.REQUIRED,isolation= Isolation.READ_COMMITTED)
	@Override
	public void purchase(int userId, String isbn) {
		//1.获取要买的图书的价格
		double bookPrice = bookShopDao.getBookPriceByIsbn(isbn);
//		System.out.println(bookPrice);
		//2.更新图书的库存
		bookShopDao.updateBookStock(isbn);
		//3.更新用户的余额
		bookShopDao.updateAccountBalance(userId, bookPrice);
//		double bookPriceByIsbn = bookShopDao.getBookPriceByIsbn(isbn);
//		System.out.println(bookPriceByIsbn);
	}
//测试方法
@Test
	void testCashier() {
		Cashier cashier = (Cashier) ioc.getBean("cashier");
		//创建List
		List<String> isbns = new ArrayList<>();
		isbns.add("1001");
		isbns.add("1002");
		//去结账
		cashier.checkout(1, isbns);
	}

数据库:

BOOK表 ISBN NAME PRICE
1001 第一本书 60
1002 第二本书 50
ACCOUNT表 ID NAME BALANCE(余额)
1 张三 100
BOOKSTOCK表 ISBN STOCK(库存)
1001 100
1002 100

1. REQUIRED

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

2. REQUIRES_NEW

  • 分析
    当bookService的purchase()方法被另一个事务方法checkout()调用时,它开启一个新的事务,此时的事务传播类型为REQURIES_NEW。每次调用purchase()方法都将生成一个新的事务,即结果为1001购买成功,1002购买失败
  • 写法
@Transactional(propagation= Propagation.REQUIRES_NEW)

3. 其他几种同理

事务的隔离级别

数据库事务并发问题

假设有现在有两个事务:Transaction01和 Transaction02

脏读

  • 当前事务读到了了其他事物更新还未提交的数据
    ① Transaction01将某条记录的AGE值从20修改为30
    ② Transaction02读取了Transaction01更新后的值:30
    ③ Transaction01回滚,AGE值恢复到了20
    ④ Transaction02读到的30就是一个无效值

不可重复读

  • 在读取期间,其他事务修改了值,则获取的值不一致
    ① Transaction01读取了AGE值为20
    ② Transaction02将AGE值修改为30
    ③ Transaction01再次读取AGE值为30,和第一次读取不一致

幻读

① Transaction01读取了STUDENT表中的一部分数据
②Transaction02向STUDENT表插入了新的数据
③ Transaction01读取STUDENT表时,多出了一些行

事物隔离级别

读未提交 Isolation.READ_UNCOMMITTED

脏读、幻读、不可重复读都无法解决

	@Transactional(propagation= Propagation.xxx,isolation= Isolation.READ_UNCOMMITTED)

允许Transaction01读取Transaction02未提交的修改

读已提交 Isolation.READ_COMMITTED

	@Transactional(propagation= Propagation.xxx,isolation= Isolation.READ_COMMITTED)

要求Transaction01只能读取Transaction02已提交的修改

可重复读: Isolation.REPEATABLE_READ

	@Transactional(propagation= Propagation.xxx,isolation= Isolation.REPEATABLE_READ)

确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其他事务对这个字段进行更新

串行化 Isolation.SERIALIZABLE

	@Transactional(propagation= Propagation.xxx,isolation= Isolation.SERIALIZABLE)

确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其他事务对这个表进行添加、更新、删除操作,可以避免任何并发问题,但性能十分

各个隔离级别解决并发问题的能力

脏读 幻读 不可重复读
READ_UNCOMMITTED
READ_COMMITTED ×
REPEATABLE_READ × ×
SERIALIZABLE × × ×

各种数据库产品对事务隔离级别的支持程度

Oracle MySQL
READ_UNCOMMITTED ×
READ_COMMITTED √ (默认)
REPEATABLE_READ × √ (默认)
SERIALIZABLE

你可能感兴趣的:(学习笔记)