数据库事务的特性ACID、隔离级别、MVCC、解决幻读

1. 解释下事务及其特性ACID?

  事务是一组操作,这组操作的各个单元要么全都成功,要么全都失败,在Mysql中,事务是在引擎层实现的,而 Mysql 默认使用的就是支持事务的 InnoDB 引擎。事务有四个特性 ACID:

  • 原子性(Atomicity):指一个事务不可分割,事务中的操作要么全都成功,要么全都失败。
  • 一致性(Consistency):指事务将数据库从一个一致性状态转换到另一个一致性状态,而数据库的完整性没有被破坏。
  • 隔离性(Isolation):指多个事务之间相互隔离、互不干扰,也就是事务提交前对其他事务都不可见。
  • 持久性(Durability):指事务一旦提交,所做的修改就会永久保存到数据库中。

3. 事务的隔离级别和存在的问题

  • 如何设置隔离级别:

    • 通过 set xxx transaction isolation level read commited 来设置隔离级别。
  • 事务的隔离级别主要用于解决脏读、不可重复读和幻读。

四种隔离级别:
  • 读未提交: 指允许读取尚未提交的数据,是最低的隔离级别。会产生脏读、不可重复读和幻读。
  • 读已提交:指事务只能读到已经提交的数据。避免了脏读,但依然会产生不可重复读和幻读。
  • 可重复读:指同一个事务多次读取同一个数据,结果一致。避免了脏读和不可重复读,会产生幻读。它是mysql默认的隔离级别。
  • 串行化:指强制事务串行执行,隔离级别最高,并发性能最低。避免了脏读、不可重复读和幻读。
    (较低级别的隔离可以执行更高的并发,系统开销也更低)
存在的问题:
  • 脏读: 指某一事务读取到了另一事务未提交的脏数据,违反了数据库的隔离性。解决方法:采用读已提交的隔离级别。(脏数据和脏页是不同的概念,脏页指的是缓冲池中被修改的页还没有刷新到磁盘中,它是由于数据库和磁盘异步造成的,最终刷新后依然能达到一致性,而且异步操作还能提高性能。而脏数据指的是事务对缓冲池中行记录的修改还没有被提交,导致一个事务读到另一个事务未提交的数据)
  • 不可重复读: 指的是在一个事务内多次读取同一个数据,而在这个期间,另一个事务对这个数据执行了更新操作并提交了,导致前一个事务两次读取的数据不一样,违反了数据库的一致性。解决方法:采用行级锁防止数据被修改。
  • 幻读: 指事务在读取某个范围的数据时,另一个事务又在该范围内插入了新的行,导致后一次查询看到了前一次查询没看到的行。解决方法:采用间隙锁,对索引中的间隙进行锁定,防止了幻影行的插入。
    (不可重复读注重于数据的修改,而幻读注重于数据的插入)
mysql是如何解决幻读的?
  • MySQL的InnoDB存储引擎默认的事务隔离级别是可重复读,并且它有一个 MVCC 多版本并发控制的机制,它在每行记录后面保存了两个隐藏的列。这两个列一个保存行的创建时间,一个保存行的删除时间,这里的时间指的是系统版本号,每当修改数据时,版本号加一。读操作通过 Undo 读取的是数据之前的历史版本,所以不会阻塞写操作,提高了数据库并发读写的性能。同时还可以解决快照读的幻读问题,快照读指的是生成一个事务快照,之后都从这个快照中获取数据,所以就不会看到新插入的行,解决了幻读的问题,比如执行 select 操作时会执行快照读。而对数据进行修改的操作采用的是当前读,也就是读取数据的最新版本,比如常见的 update/insert/delete(还有 select … for update、select … lock in share mode)都是当前读,对于当前读的幻读问题,MVCC是无法解决的,所以需要使用 next-key locks ,它由记录锁和间隙锁组成,记录锁对索引进行加锁,而间隙锁可以锁住数据行的间隙,于是可以避免幻影行的插入,解决了当前读的幻读问题。
InnoDB 锁的算法有哪几种?
  • Record lock:记录锁,单条索引记录上加锁,锁住的是索引,而非记录本身。
  • Gap lock:间隙锁,在索引记录的间隙中加锁,并不包括该索引记录本身。
  • Next-key lock:Record lock 和 Gap lock 的结合,既锁住了索引,又锁住了索引间的间隙。

4. MVCC(多版本并发控制)

  • MVCC可以看做是行级锁的一个变种, 通过保存数据在某个时间点的快照来实现,它尽量避免了加锁操作, 因此开销教低,实现了非阻塞的读操作,写操作也只锁定必要的行,应对高并发事务,MVCC比单纯的加锁更高效。

  • (数据库的可重复读是如何实现的?)InnoDB默认的隔离级别是可重复读,使用MVCC实现,它在每行记录后面保存了两个隐藏列。这两个列一个保存行的创建时间,一个保存行的删除时间,这里的时间指的是系统版本号,每当修改数据时,版本号加一。读操作通过 Undo 读取的是数据之前的历史版本,所以不会阻塞写操作,提高了数据库并发读写的性能。同时还可以解决快照读的幻读问题,快照读指的是生成一个事务快照,之后都从这个快照中获取数据,所以就不会看到新插入的行,解决了幻读的问题,比如执行 select 操作时会执行快照读。(MVCC解决不了当前读的幻读问题,当前读需要间隙锁来解决)

  • MVCC只作用于读已提交可重复读这两个隔离级别,因为读未提交总是读取最新的数据行, 而不是符合当前事务版本的数据行,而串行化则会对所有读取的行都加锁。

InnoDB是如何实现事务的?(日志

  • 实现事务的原子性:通过回滚日志 Undo Log 来记录数据修改前的状态,如果事务执行失败,就通过Undo Log中的记录对数据进行回滚。
  • 实现事务的一致性:通过重做日志 Redo Log 来记录数据修改后的状态,如果判断出数据异常,就需要进行回滚。
  • 实现事务的隔离性:通过对事务操作的数据进行加锁来实现,有共享锁和排他锁,保证了事务提交前对其他事务都不可见。
  • 实现事务的持久性:如果数据库崩溃,就通过配合使用 Undo Log 和 Redo Log 对事务进行恢复,以此来保证事务的持久性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值