Spring事务及工作中的使用

什么是事务:
数据库的事务是指一组sql语句组成的数据库逻辑处理单元,在这组的sql操作中,要么全部执行成功,要么全部执行失败。
就假如小明给小红存钱,逻辑上一定是小明扣钱与小红加钱是一起成功或失败的。(不可以出现只有一方成功的情况)
事务演示


事务的四大特征:
事务包含原子性(Atomicity)一致性(Consistent)隔离性(Isalotion)持久性(Durable),简称为ACID

原子性:是指对数据的修改要么全部执行成功要么全部失败实现事务的原子性,是基于日志的Redo/Undo机制
日志的Redo/Undo机制 是指它们将所有对数据的更新操作都写到日志中Redo log用来记录某数据块被修改后的值,可以用来恢复未写入 data file 的已成功事务更新的数据Undo log是用来记录数据更新前的值保证数据更新失败能够回滚

一致性:是指执行事务前后的状态要一致,可以理解为数据一致性

隔离性:指事务之间相互隔离,不受影响,这个与事务设置的隔离级别有密切的关系

持久性:持久性则是指在一个事务提交后,这个事务的状态会被持久化到数据库中,也就是事务提交,对数据的新增、更新将会持久化到数据库中

事务的隔离级别:

  1. Read uncommitted (读未提交):最低级别,以上问题均无法解决。
  2. Read committed (读已提交):读已提交,可避免脏读情况发生。
  3. Repeatable Read (可重复读)确保事务可以多次从一个字段中读取相同的值,在此事务持续期间,禁止其他事务对此字段的更新,可以避免脏读和不可重复读,仍会出现幻读问题
  4. Serializable (串行化):最严格的事务隔离级别,要求所有事务被串行执行,不能并发执行可避免脏读、不可重复读、幻读情况的发生

以上的隔离级别是从低到高的,越高的隔离级别性能就越差。Mysql默认的隔离级别为第三级Repeatable Read

问题含义
脏读A事务读取B事务尚未提交的更改数据
不可重复读不可重复读是指A事务读取了B事务已经提交的更改数据。假如A在取款事务的过程中,B往该账户转账100,A两次读取的余额发生不一致。
幻读A事务读取B事务提交的新增数据,会引发幻读问题

不可重复读和幻读的区别是:不可重复读是指读到了已经提交的事务的更改数据(修改或删除),幻读是指读到了其他已经提交事务的新增数据
对于这两种问题解决采用不同的办法,防止读到更改数据,只需对操作的数据添加行级锁,防止操作中的数据发生变化;防止读到新增数据,往往需要添加表级锁,将整张表锁定,防止新增数据


查看Mysql数据库当前的隔离级别

select @@tx_isolation;

设置Mysql数据库的隔离级别

set tx_isolation = '隔离级别名称'

工作中一般项目会使用(Read Commited)读已提交作为隔离级别。因为RC比RR在锁方面,由于RC不使用间隙锁解决幻读问题,所以并发要好于RR,并且 不容易出现死锁


我们了解完事务的隔离后再来了解一下我们如何在工作中使用事务吧。

在SpringBoot中有这么一个注解可以进行事务管理

@Transactional(rollbackFor = Exception.class)

当我们执行某个方法需要进行事务管理时,我们就需要在类上添加此注解
rollbackFor是指发生了什么异常的时候会自动回滚

当我们需要手动回滚的时候,我们可以在方法中调用下面的方法进行回滚

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

SpringBoot中的事务管理需要注意如下问题
1.方法的修饰符必须为public可以使用final不可以使用static等其他修饰符
2.会默认对RuntimeException及其子类进行回滚遇到Exception及其子类则不会默认进行回滚,需要使用rollbackFor属性变为Exception
3.如果 同一个类普通方法A调用事务方法B方法B的事务不会生效 ,因为 同类方法调用不走代理无法增强(重要)
4.在多线程的情况下事务是不会传递到子线程中 的,需要在子方法中单独添加事务注解
5.如果方法中有try…catch…处理try中的代码则脱离了事务的管理,若需要事务生效需要手动在catch中throw new RuntimeException(“XXXXX”)

如何处理同一个类的事务方法互相调用时事务失效问题?
首先我们要启动类上添加注解启用exposeProxy

@EnableAspectJAutoProxy(exposeProxy = true)

当我们在方法A中调用事务方法B的时候创建代理对象,调用对象的事务方法

//获得代理对象
B b = (B) AopContext.currentProxy();
//调用对象b的事务方法method
b.method();

在事务的传播过程中,A方法调用B方法,需要B方法单独开一个事务的时候,我们要在事务注解中添加此属性

@Transactional(propagation = Propagation.REQUIRES_NEW)

表示会单独新开一个事务

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值