目录
1.事务回顾
1.1什么是事务
1.2事务的四大重要特性(ACID)
1.3事务的操作
2.Spring中事务的实现
2.1编程式事务(了解)
2.2声明式事务@Transactional
3.@Transactional作用
3.1重新抛出异常
3.2手动回滚事务
1.事务回顾
在数据库阶段我们已经学习过事务了
1.1什么是事务
事务是一组操作的集合,是一个不可分割的操作.
事务会把所有的操作作为一个整体,一起向数据库提交或者是撤销操作请求.所以这组操作要么同时成功,要么同时失败.
1.2事务的四大重要特性(ACID)
事务具有以下四个重要特性,通常称为 ACID 特性:
-
原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败回滚。如果事务中的某个操作失败,整个事务会撤销,就好像整个事务从未执行过一样。
-
一致性(Consistency):事务执行的结果必须使数据库从一个一致性状态转变到另一个一致性状态。这意味着数据库中的数据必须始终满足预定的规则和约束。
-
隔离性(Isolation):多个事务并发执行时,它们之间相互隔离,一个事务的执行不能被其他事务干扰。每个事务都感觉自己在独立地操作数据库。
-
持久性(Durability):一旦事务成功提交,其对数据库的更改就会永久保存,即使系统出现故障也不会丢失。
1.3事务的操作
事务的操作主要有三步:
1.开启事务:start transaction/begin(一组操作前开启事务)
2.提交事务:commit(这组操作全部成功,提交事务)
3.回滚事务:rollback (这组操作中间任何一个操作出现异常,回滚事务)
-- 开启事务
start transaction;
-- 提交事务
commit;
-- 回滚事务
rollback;
2.Spring中事务的实现
前面课程我们讲了MySQL的事务操作,Spring对事务也进行了实现.
Spring中的事务操作分为两类:编程式事务、声明式事务
2.1编程式事务(了解)
编程式事务为手动写代码操作事务,Spring手动操作事务和上面MySQL操作事务类似,有3个重要操作步骤:
- 开启事务(获取事务)
- 提交事务
- 回滚事务
SpringBoot内置了两个对象:
1.DataSourceTransactionManager事务管理器.用来获取事务(开启事务),提交或回滚事务
2.TransactionDefinition是事务的属性,在获取事务的时候需要将TransactionDefinition传递进去从而获得一个事务TransactionStatus
我们还是根据代码的实现来学习:
@RequestMapping("/user")
@RestController
public class UserController {
// JDBC 事务管理器
@Autowired
private DataSourceTransactionManager dataSourceTransactionManager;
// 定义事务属性
@Autowired
private TransactionDefinition transactionDefinition;
@Autowired
private UserService userService;
@RequestMapping("/registry")
public String registry(String name,String password){
// 开启事务
TransactionStatus transactionStatus = dataSourceTransactionManager
.getTransaction(transactionDefinition);
//⽤户注册
userService.registryUser(name,password);
//提交事务
dataSourceTransactionManager.commit(transactionStatus);
//回滚事务
//dataSourceTransactionManager.rollback(transactionStatus);
return "注册成功 ";
}
}
观察事务提交:
//提交事务
dataSourceTransactionManager.commit(transactionStatus);
运行程序: http://127.0.0.1:8080/user/registry?name=admin&password=admin
观察数据库的结果, 数据插入成功.
观察事务回滚:
//回滚事务
dataSourceTransactionManager.rollback(transactionStatus);
运行程序:
观察数据库, 虽然程序返回"注册成功", 但数据库并没有新增数据.
以上代码虽然可以实现事务, 但操作也很繁琐, 有更简单的实现方法:声明式事务
2.2声明式事务@Transactional
声明式事务的实现很简单,只需要在需要事务的方法上添加@Transactional注解就可以实现了。无需手动开启事务和提交事务,进入方法时自动开启事务,方法执行完会自动提交事务,如果中途发生了没有处理的异常会自动回滚事务.
我们来看代码实现:
@RequestMapping("/trans")
@RestController
public class TransactionalController {
@Autowired
private UserService userService;
@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
//⽤⼾注册
userService.registryUser(name,password);
return "注册成功 ";
}
}
运行程序,发现数据插入成功.
修改程序, 使之出现异常
@Slf4j
@RequestMapping("/trans")
@RestController
public class TransactionalController {
@Autowired
private UserService userService;
@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
//⽤⼾注册
userService.registryUser(name,password);
log.info("⽤户数据插⼊成功");
//强制程序抛出异常
int a = 10/0;
return "注册成功 ";
}
}
运行程序:
发现虽然日志显示数据插入成功, 但数据库却没有新增数据, 事务进行了回滚.
我们一般会在业务逻辑层当中来控制事务,因为在业务逻辑层当中,一个业务功能可能会包含多个数据访问的操作,在业务逻辑层来控制事务,我们就可以将多个数据访问操作控制在一个事务范围内.上述代码在Controller中书写,只是为了方便学习.
3.@Transactional作用
@Transactional可以用来修饰方法或类:
修饰方法时:只有修饰public方法时才生效(修饰其他方法时不会报错,也不生效)[推荐]
修饰类时:对@Transactional修饰的类中所有的public方法都生效.
方法/类被@Transactional注解修饰时,在目标方法执行开始之前,会自动开启事务,方法执行结束之后,自动提交事务.
如果在方法执行过程中,出现异常,且异常未被捕获,就进行事务回滚操作。如果异常被程序捕获,方法就被认为是成功执行,依然会提交事务。
修改上述代码,对异常进行捕获
@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
//⽤户注册
userService.registryUser(name,password);
log.info("⽤户数据插⼊成功");
//对异常进⾏捕获
try {
//强制程序抛出异常
int a = 10/0;
}catch (Exception e){
e.printStackTrace();
}
return "注册成功 ";
}
运行程序, 发现虽然程序出错了, 但是由于异常被捕获, 所以事务依然得到了提交. 如果需要事务进行回滚, 有以下两种方式:
3.1重新抛出异常
@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
//⽤户注册
userService.registryUser(name,password);
log.info("⽤户数据插⼊成功");
//对异常进⾏捕获
try {
//强制程序抛出异常
int a = 10/0;
}catch (Exception e){
//将异常重新抛出去
throw e;
}
return "注册成功 ";
}
重新抛出异常后事务会进行回滚
3.2手动回滚事务
使用TransactionAspectSupport.currentTransactionStatus()得到当前的事务,并设置setRollbackOnly
@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
//⽤⼾注册
userService.registryUser(name,password);
log.info("⽤户数据插⼊成功");
//对异常进⾏捕获
try {
//强制程序抛出异常
int a = 10/0;
}catch (Exception e){
// ⼿动回滚事务
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return "注册成功 ";
}
代码解释:
TransactionAspectSupport是 Spring 框架中与事务处理相关的一个支持类。 currentTransactionStatus()方法用于获取当前正在执行的事务的状态对象。 setRollbackOnly()方法用于将获取到的当前事务状态设置为只回滚。这意味着无论事务中后续的操作结果如何,整个事务都会被回滚,不会进行提交。