三、声明式事务
声明式事务:以前通过复杂编程来编写一个事务,替换为只需要告诉Spring哪个方法是事务方法即可,由Spring进行事务控制,基于Spring AOP环绕通知。
事务管理器代码的固定模式作为一种横切关注点,可以通过Spring AOP方法模块化,借助Spring AOP框架实现生命是事务管理,事务切面即事务管理器
不同的数据库连接使用不同的事务管理器
xml中配置事务管理器,导入tx名称空间xmlns:tx="www.springframework.org/schema/tx"
<!--事务管理器配置--> <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--开启基于注解的配置模式--> <tx:annotation-driven transaction-manager="dataSourceTransactionManager" /> 复制代码
验证事务
在BookService的checkout方法中增加异常代码
public void checkout(String username, String isbn){ // 1.减库存 bookDao.updateStock(isbn); // 异常代码 System.out.println(10/0); // 2.减余额 int price = bookDao.getPrice(isbn); bookDao.updateBalance(username,price); } 复制代码
执行测试方法,检查数据库,库存被扣减1,而余额没有变化
将库存恢复至1000,余额恢复至10000,在checkout方法上增加@Transactional注解,再次测试 控制台报错,余额和库存数量没有变化,删除checkout方法中的异常代码,再次进行测试。
均可以正常扣减
四、@Transactional注解
@Transactional注解的属性
- isolation:设置事务隔离级别
- propagation:设置事务传播行为
- noRollbakcFor:设置哪些异常事务不回滚,指定异常的class,是一个数组
- noRollbackForClassName:设置哪些事务不回滚,指定异常的全类名,是一个数组
- rollbackFor:设置哪些异常事务回滚,指定异常的class,是一个数组
- rollbackForClassName:设置哪些异常事务回滚,指定异常的全类名,是一个数组
- readOnly:布尔类型,设置事务为只读事务
- timeout:超时时间,事务执行时间超出设定的时间自动终止并回滚
timeout
int类型,单位是秒,超时时间,事务执行超过指定的时间会自动停止并回滚
@Transactional(timeout = 3) public void checkout(String username, String isbn){ // 1.减库存 bookDao.updateStock(isbn); // 休眠5s try { Thread.sleep(5000); } catch (Exception e){ e.printStackTrace(); } // 2.减余额 int price = bookDao.getPrice(isbn); bookDao.updateBalance(username,price); } 复制代码
执行测试方法,库存数和余额数无变化
readOnly
默认为false,readOnly=true可以设置事务为只读事务,实现对事务进行优化,提高查询速度,忽略事务的commit等操作
@Transactional(readOnly = true) public void checkout(String username, String isbn){ // 1.减库存 bookDao.updateStock(isbn); // 2.减余额 int price = bookDao.getPrice(isbn); bookDao.updateBalance(username,price); } 复制代码
执行测试方法
事务中有更新操作,是不能设置readOnly的
noRollbackFor 和 noRollbackForClassName
- 运行时异常,可以不用处理,默认都回滚
- 编译时异常,使用try-catch处理或者在方法上声明throws,默认不回滚
noRollbackFor可以配置指定异常不回滚,即让原来默认回滚的异常不回滚 noRollbackForClassName指定不回滚的异常的全类名,noRollbackFor指定的是异常的类型,它们都是数组
//@Transactional(noRollbackForClassName = {"java.lang.ArithmeticException"}) @Transactional(noRollbackFor = {ArithmeticException.class}) public void checkout(String username, String isbn) { // 1.减库存 bookDao.updateStock(isbn); // 2.减余额 int price = bookDao.getPrice(isbn); bookDao.updateBalance(username, price); // 增加运行时异常,默认回滚 System.out.println(10 / 0); } 复制代码
将stock恢复至1000,余额恢复至10000,执行测试
余额和库存都进行了扣减,实现了让原本默认回滚的不回滚
rollBackFor 和 rollBackForClassName
指定让原本不回滚的异常回滚,所有的编译时异常默认不会滚
// @Transactional(rollbackForClassName = {"java.io.FileNotFoundException"}) @Transactional(rollbackFor = {FileNotFoundException.class}) public void checkout(String username, String isbn) throws FileNotFoundException { // 1.减库存 bookDao.updateStock(isbn); // 2.减余额 int price = bookDao.getPrice(isbn); bookDao.updateBalance(username, price); // 增加编译时异常,默认不回滚 new FileInputStream("../stark.txt"); } 复制代码
将stock恢复至1000,余额恢复至10000,执行测试
余额和库存没有变化