1.什么是事务
在数据库中,事务是数据库操作的最小单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行。换句话说,事务是一组不可再分割的操作集合(工作逻辑单元)。
事务有四大特性:
- 原子性:事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做 。
- 一致性:事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。当数据库只包含事务成功提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。
- 隔离性:一个事务的执行不能被其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
- 持续性:也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。
2.Java Spring中的事务
说是Java Spring中的事务,事实上与数据库中的事务的定义类似,就是在Java Spring中实现多个方法的一致执行或回滚,用来确保数据的完整性和一致性。
Spring 实现事务管理有如下两种方式:
编程式事务管理与声明式事务管理。前者是将事务管理代码嵌入到业务方法中来控制事务的提交和回滚,由于需要额外增加大量代码,因此常常使用声明式事务管理。
如何实现声明式事务
声明式事务的原理很简单:对方法的前后进行拦截,然后在目标方法开始之前创建或加入一个事务,在执行完毕之后根据执行情况提交或回滚事务。整个过程通过@Transactional注解实现。具体步骤如下:
- 添加spring-aspects-4.3.10.RELEASE.jar包
-
在Spring配置文件中添加如下配置:
<!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 启用事务注解 --> <tx:annotation-driven transaction-manager="transactionManager"/>
-
在Service层public方法上添加事务注解——@Transactional(注意:不能在protected、默认或者private的方法上使用@Transactional注解,否则无效。)
@Transactional注解属性
1.rollbackFor和rollbackForClassName
指定对哪些异常回滚事务。默认情况下,如果在事务中抛出了运行时异常(继承自RuntimeException异常类),则回滚事务;如果没有抛出任何异常,或者抛出了检查时异常,则依然提交事务。
@Service
public class CouponService implements ICouponService {
@Autowired
private IBookDao bookDao;
@Autowired
private IMoneyDao moneyDao;
@Autowired
private ICouponDao couponDao;
//立即购买
@Override
@Transactional
public boolean insert(String userId,String bookId, int count){
if(bookDao.enough(bookId, count)) {//书籍足够
//书籍表库存递减
bookDao.update(bookId, count);
}
double price = bookDao.getPrice(bookId);
double total = price*count;
if(moneyDao.enough(userId, total)) {//余额足够
//订单表添加数据
Coupon coupon = new Coupon();
coupon.setId(UUID.randomUUID().toString());
coupon.setUserId(userId);
coupon.setBookId(bookId);
coupon.setTotal(total);
couponDao.insert(coupon);
//钱包表递减
moneyDao.update(userId, total);
}
return true;
}
}
书籍表中有50本书籍,每本书10元,一个人钱包有1元,欲买50本,则该行代码抛出MoneyException异常,但由于该异常为运行时异常,所以回滚事务,即上述代码中“bookDao.update(bookId, count);”行代码执行失效。
上述事件中,若MoneyException异常是检查时异常,则依旧会抛出该异常,但不会回滚,急救提交事务,即“bookDao.update(bookId, count);”行代码执行生效。
若此时在@Transactional后加上rollbackFor,即</