事务的传播行为可以由传播属性指定
传播属性 | 描述 |
---|---|
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 |
@Transactional(propagation= Propagation.REQUIRED)
@Transactional
@Transactional(propagation= Propagation.REQUIRES_NEW)
假设有现在有两个事务:Transaction01和 Transaction02
① Transaction01读取了STUDENT表中的一部分数据
②Transaction02向STUDENT表插入了新的数据
③ Transaction01读取STUDENT表时,多出了一些行
脏读、幻读、不可重复读都无法解决
@Transactional(propagation= Propagation.xxx,isolation= Isolation.READ_UNCOMMITTED)
允许Transaction01读取Transaction02未提交的修改
@Transactional(propagation= Propagation.xxx,isolation= Isolation.READ_COMMITTED)
要求Transaction01只能读取Transaction02已提交的修改
@Transactional(propagation= Propagation.xxx,isolation= Isolation.REPEATABLE_READ)
确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其他事务对这个字段进行更新
@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 | √ | √ |