1.事务就是一系列的动作,它们被当作一个单独的工作单元,这些动作要么全部完成,要么全部不起作用;
2.四个关键属性:
-原子性:事务是一个原子操作,由一系列动作组成,事物的原子性确保要么全部完成,要么完全不起作用;
-一致性:一旦所有事物动作完成,事物就会被提交。数据和资源就处于一种满足业务规则的一致性状态中;
-隔离性:可能有许多事物会同时处理相同的数据,因此每个事务都应该与其他事务隔离开,防止数据损坏;
-持久性: 一旦事务完成,无论发生什么系统错误,他的结果都不应该受到影响。通常情况下,事物的结果被写入到持 久化存储器中。
3.spring的声明式事务的使用:
配置文件的配置:applicationContext.xml
<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 启用事务注解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
在Serviceimpl的方法上面加上事务的注解:
@Transactional
@Override
public void purchase(String username, String isbn) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {}
//1. 获取书的单价
int price = bookShopDao.findBookPriceByIsbn(isbn);
//2. 更新数的库存
bookShopDao.updateBookStock(isbn);
//3. 更新用户余额
bookShopDao.updateUserAccount(username, price);
}
4.事务的传播属性:
当事务方法被另一个事务方法调用的时候,必须指定事务应该如何传播。例如:方法可能继续在现有的事务中运行,也可能开启一个新事务,并在自己的事务中运行。
常用的事物传播行为:
-REQURED:如果有事务在运行,当前的方法就在这个事务内运行,否则,就启用一个新的事务,并在自己的事务 内运行;
-REQURES_NEW: 当前方法必须启动新事务,并在它自己的事物内运行,如果有事务正在运行,应该将它挂起。
Demo:描述:书店买书:买一本书是一个事务;同时买多本书也设置成一个事务,那么当剩余的钱只够每一本书的时候这个事 务如何设置传播属性?
代码实现:买一本书的事物:
//添加事务注解
//1.使用 propagation 指定事务的传播行为, 即当前的事务方法被另外一个事务方法调用时
//如何使用事务, 默认取值为 REQUIRED, 即使用调用方法的事务
//REQUIRES_NEW: 事务自己的事务, 调用的事务方法的事务被挂起.
@Transactional(propagation=Propagation.REQUIRES_NEW)
@Override
public void purchase(String username, String isbn) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {}
//1. 获取书的单价
int price = bookShopDao.findBookPriceByIsbn(isbn);
//2. 更新数的库存
bookShopDao.updateBookStock(isbn);
//3. 更新用户余额
bookShopDao.updateUserAccount(username, price);
}
买多本书:
@Service("cashier")
public class CashierImpl implements Cashier {
@Autowired
private BookShopService bookShopService;
//买多本书也使用了事务的注解
@Transactional
@Override
public void checkout(String username, List<String> isbns) {
for(String isbn: isbns){
bookShopService.purchase(username, isbn);
}
}
}
调用方法实现:
@Test
public void testTransactionlPropagation(){
cashier.checkout("AA", Arrays.asList("1001", "1002"));
}
此时银行卡里的余额只够买1002这本书,则事务如何处理?
@Transactional(propagation=Propagation.REQUIRES_NEW)
此时在当前事务(买多本书)中,每买一本书都是使用自己(即purchase())的事务,所以可以实现买完第一本书的事务,之后在买第二本的时候由于余额不足,导致买不了事务回滚。
Tx1:checkouot();
Tx2:第一个purchase();
Tx3:第二个purchase();