事务定义:
将一组操作封装成一个执行单元,要么全部成功,要么全部失败。
事务的意义:
当执行某个操作,例如支付操作时(分为先将钱从个人账户扣除和将他人账户新增两个操作),如果这两个操作不能同时成功或者失败,那么就会出现财产问题。而使用事务就能够很好的解决这个问题。
Spring 中的事务操作分为两类:
Spring 手动操作事务分为三个步骤:
SpringBoot 内置了两个对象,可以用来处理事务:
具体代码实现如下:
@RestController
@RequestMapping("user")
public class UserController {
// JDBC 事务管理器
@Resource
private DataSourceTransactionManager dataSourceTransactionManager;
// 定义事务属性
@Resource
private TransactionDefinition transactionDefinition;
@RequestMapping("/test1")
public String test1(){
// 开启事务
TransactionStatus transaction = dataSourceTransactionManager.getTransaction(transactionDefinition);
// 执行数据库操作
// 提交事务
dataSourceTransactionManager.commit(transaction);
// 回滚事务
dataSourceTransactionManager.rollback(transaction);
return "测试完成!";
}
}
声明式事务的实现相较于手动实现要简单很多,只需要在需要添加事务的方法上加上 @Transactional
注解就可以,无需手动开启事务和提交事务,进入方法时会自动开启事务,方法执行完成会自动提交事务,如果中途发生了没有处理的异常就会自动回滚事务。
具体代码实现如下:
@RestController
@RequestMapping("user")
public class UserController {
@Transactional
@RequestMapping("/test2")
public String test2(){
// 执行数据库操作
return "测试完成!";
}
}
当我们在执行完数据库操作后,有一个语句出现异常,通过 @Transactional 注解就能进行回滚。
通过上文我们了解到,在需要的方法上添加 @Transactional 注解,就能自动开启事务。接下来将会具体了解下 @Transactional 的使用细节。
@Fransactional 可以用来修饰方法或类:
参数 | 作用 |
---|---|
value | 当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器。 |
transactionManager | 当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器。 |
propagation | 事务的传播行为,默认值为 Propagation.REQUIRED。 |
isolation | 事务的隔离级别,默认值为 Isolation.DEFAULT。 |
timeout | 事务的超时时间,默认值为-1(表示没有超时时间)。如果超过该超时时间显示但事务还没有完成,则自动回滚事务。 |
readOnly | 指定事务是否为只读事务,默认值为 false。为了忽略那些不需要事务的方法,比如读取数据,可以设置为 true。 |
rollbackFor | 用于指定能够被触发事务回滚的异常类型,可以指定多个异常类型。 |
rollbackForClassName | 用于指定能够被触发事务回滚的异常类型,可以指定多个异常类型。 |
noRollbackFor | 抛出异常的类型,不回滚事务,也可以指定多个异常类型。 |
noRollbackForClassName | 抛出异常的类型,不回滚事务,也可以指定多个异常类型。 |
注意: rollbackFor 是将指定的非运行时异常进行回滚。
@Transactional 在异常被捕获的情况下,不会进行事务的自动回滚。
注意: 默认情况下,Spring 中的事务如果遇到运行时异常,事务是会进行回滚的,但遇到非运行时异常,事务不会自动回滚。可以设置 rollbackFor 来解决非运行时异常不会被回滚的问题。
示例代码如下:
@RequestMapping("/test3")
@Transactional
public String test3(@RequestParam String username, @RequestParam String pwd) {
// 插⼊数据库
int result = userService.addUser(username, pwd);
try {
// 执⾏了异常代码
int i = 10 / 0;
} catch (Exception e) {
}
return "测试完成!";
}
以上代码虽然出现了算数异常,但是由于主动捕获了,因此不会进行事物的回滚,数据库中会插入该条数据。
如果要解决出现异常事务不能自动回滚的问题,以下提供两种解决方案:
@RequestMapping("/test3")
@Transactional
public String test3(@RequestParam String username, @RequestParam String pwd) {
// 插⼊数据库
int result = userService.addUser(username, pwd);
try {
// 执⾏了异常代码
int i = 10 / 0;
} catch (Exception e) {
// 将异常重新抛出
throw e;
}
return "测试完成!";
}
TransactionAspectSupport.currentTransactionStatus()
得到当前的事务,然后设置回滚方法 setRollbackOnly
就可以实现回滚。示例代码如下:@RequestMapping("/test3")
@Transactional
public String test3(@RequestParam String username, @RequestParam String pwd) {
// 插⼊数据库
int result = userService.addUser(username, pwd);
try {
// 执⾏了异常代码
int i = 10 / 0;
} catch (Exception e) {
// 手动回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return "测试完成!";
}
@Transactional 是基于 AOP 实现的,AOP 又是使用了动态代理实现的。如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理;如果目标对象没有实现接口,会使用 CGLIB 动态代理。@Transactional 在开始执行业务之前,通过代理先开启事务,在执行成功之后再提交事务。如果中途遇到异常,则回滚事务。
@Transactional 实现思路:
@Transactional 具体执行细节:
事务有4大特性,简称为 ACID,分别如下:
在这四种特性中,只有隔离性可以设置,通过设置事务的隔离级别可以用来保障多个并发事务执行更加可控,更符合操作者的预期,是防止其它的事务影响当前事务执行的一种策略。
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | √ | √ | √ |
读已提交 | × | √ | × |
可重复度 | × | × | √ |
串行化 | × | × | × |
在数据库中可以通过以下 SQL 查询全局事务隔离级别和当前连接的事务隔离级别:
select @@global.tx_isolation,@@tx_isolation;
Spring 中事务隔离级别可以通过 @Transactional 的 Isolation 属性进行设置。
Spring 事务传播机制定义了多个包含了事务的方法在相互调用时,事务是如何在这些方法之间进行传递的。
嵌套事务和加入事务的区别:
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://t4dmw.blog.csdn.net/article/details/126216621
内容来源于网络,如有侵权,请联系作者删除!