数据库事务

本文详细解析数据库事务的ACID特性,包括原子性、一致性、隔离性和持久性,并探讨了InnoDB如何通过日志和锁机制实现这些特性。同时,文章深入分析了并发事务可能遇到的脏读、不可重复读、幻读等问题,以及如何通过不同的隔离级别避免这些问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

面试准备,仅为一家之言,无法保证理解正确性,慎,欢迎纠正

数据库事务

ACID

  • A : Atomic:原子性:指数据库事务要么完成,要么不做.是一个不可分割的原子操作;
  • C:consistency: 一致性:指事务完成要保证业务逻辑数据一致;即业务是A账户向B账户转账,无论怎么转,事务完成后必须保证A账户和B账户的总额不变;
  • I:Isolation: 隔离性: 指不同事务有自己的执行空间,各自的操作不会影响到其他事务的执行;这里可以通过设置不同的隔离级别来控制事务的隔离强度,隔离级别越高,数据一致性越好,并发性能越低;
  • D: Durability:持久性: 一旦事务成功提交,对数据的操作必须写进数据库中,即使是事务刚提交,数据库就崩溃,也要保证下一次重启时,之前的数据操作可以写到数据库中;

InnoDB对ACID的实现

事务的ACID是通过InnoDB日志和锁来保证。事务的隔离性是通过数据库锁的机制实现的,持久性通过redo log(重做日志)来实现,原子性和一致性通过Undo log来实现。UndoLog的原理很简单,为了满足事务的原子性,在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为UndoLog)。然后进行数据的修改。如果出现了错误或者用户执行了ROLLBACK语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态。
和Undo Log相反,RedoLog记录的是新数据的备份。在事务提交前,只要将RedoLog持久化即可,不需要将数据持久化。当系统崩溃时,虽然数据没有持久化,但是RedoLog已经持久化。系统可以根据RedoLog的内容,将所有数据恢复到最新的状态。
对具体实现过程有兴趣的同学可以去自行搜索扩展。

链接:https://juejin.im/post/5b5a0bf9f265da0f6523913b

数据库并发问题

  • 脏读: A事务读取了B事务尚未提交的更改数据,并使用这个数据进行后续操作,但是B事务回滚,撤销了事务,B事务更改的数据就会被恢复为原来的值,但是A事务使用了被修改的值后又进行了一系列的操作;
  • 不可重复读: 指A事务分别在B事务开始和结束后读取了被B修改的值,造成A事务的操作数据不一致;
  • 幻读: 类似不可重复读,指A事务是在B事务新增数据操作前后读取到了包括新增数据的总数据,而造成数据不一致的问题;主要是前一次读取时还满足要求,但在执行时又不满足了;
  • 不可重复读和幻读的区别有很多误解,一般的理解是不可重复读指两次读取读到修改数据,而幻读是读到新增和删除的数据,一开始我也是这样认为的,但是又有一篇博客,说到,幻读并不是这样的,而是读到的不一致影响了后续操作才叫幻读,总之,点进去看吧
  • 第一类丢失更新: 我觉得类似脏读,指A事务先读到一个值a,在后续操作前,B事务将该值修改为b,然后提交事务,然后A在原来读取到的值a的基础上继续执行,并做了修改为c,但是因为一些问题发生回滚,值被回滚到a,这时,B事务的操作就被丢失了,造成数据不一致;
  • 第二类丢失更新: 类似第一类丢失更新,指A事务先读到一个值a,然后B事务开始并将a修改为b,提交事务,但是A事务继续执行,经a修改为c,这时丢失了B事务的更新;

事务隔离级别

隔离级别脏读不可重复读幻读第一类丢失更新第二类丢失更新
READ UNCOMMITED允许允许允许不允许允许
READ COMMITED不允许允许允许不允许允许
REPEATABLE READ不允许不允许允许不允许不允许
SERIALIZABLE不允许不允许不允许不允许不允许
  • 未提交读: 一个事务可以读到另一个未提交的事务修改的值;
  • 提交读: 本事务读到的数据是最新的,也就是说一个事务内相同的query操作可以得到不同的结果(中间有其他事务提交)
  • 可重复读: 本事务的相同的多次query操作得到的结果是一样的
  • 串行读: 事务间有类似读写锁的锁机制,并发读允许,并发写不允许
  • READ UNCOMMITED拥有最高的并发度和吞吐量,而SERIALIZABLE并发量最低;
  • Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.

数据库锁机制

按所对象分可以分为表锁定和行锁定,前者对整张表锁定,后者对特定行锁定,从并发事务关系来看可以分为共享锁和独占锁;共享锁允许其他共享锁进入,排斥独占锁,而独占锁即防止共享锁也防止独占锁;

  • 行共享锁定:通过sql语句中select ... for update或者lock table in row share mode(oracle)获得共享锁定,

  • 行独占锁定:通过sql语句insert|update|delete 或者 lock table in row exclusive mode这些语句都是;

  • 表 共享锁定: 通过lock table in share mode,表共享可以防止行独占锁定和表独占锁定,允许表共享和行共享

  • 表共享行锁定 通过lock table in share row exclusive mode 显式获得,这种锁定可以防止其他回话获取一个表共享,行独占,或者表独占;只允许行共享

  • 表独占: 通过lock table in exclusive mode语句显示获得,什么都不允许

  • MyISAM使用的是表级锁, InnoDB使用的是行级锁

InnoDB行级锁算法

  • Record Lock: 单行记录上的锁
  • Gap lock: 间隙锁,锁定一段距离,不包括记录本身
  • Next-key lock: record+gap,锁定一段距离,包括记录本身
  • 三种锁的具体讲解,可以看这篇博客:InnoDB锁机制
  • 使用next-key lock主要是为了解决幻读的问题,首先看上面对幻读的理解,事务1在执行期间,先获得信息是没有id=1的数据,正准备插入id=1的数据时,发现事务2已经插入了id=1的数据,导致之后的操作失败了,整个事务也就失败了
  • RR解决幻读的问题是这样的的,还是上面的例子,事务1在查到id=1没有时,就会加上next-key lock锁住一段间隙,这样事务2就无法插入数据了,而如果数据存在,比如事务1先查数据存在,正准备删除时,会为这条记录加上写锁,导致其他事务无法先删除
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值