MySQL面试必备(三)事务篇

1. 什么是数据库事务

事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态。事务是逻辑上的一组操作,要么都执行,要么都不执行。

2. 事务的四个特征(acid)

  • 原子性(atomicity)。事务中包含的各操作要么全部成功,要么全部失败回滚。。

  • 一致性(consistency)。事务执行的结果必须是使数据库从一个一致性状态转变到另一个一致性状态。因此当数据库只包含成果事务提交的结果时,就说数据库处于一致性状态。如果数据库系统运行中发生故障,有些事务尚未完成就被迫中断,这些未完成的事务对数据库所作的修改有一部分已经写入物理数据库,这时数据库就处于不正确的状态,或者说不一致的状态。---------举例说明:最经典的就是转账,A 转给 B 10元,A 的账户余额将减少 10 而 B 的账户余额将增加 10。如果在转账过程中突然系统崩溃或者断网,导致 A 少了 10 元而 B 的余额没有增加,很明显出了问题。

  • 隔离性(isolation)。一个事务所进行的修改在最终提交之前,对其他事务不可见。

  • 永久性(durability)。数据一旦提交,其所作的修改将永久的保留在数据库中。

3. 数据库的并发一致性问题(脏不幻丢)

当多个事务并发执行时,可能出现以下问题。

  • 脏读。事务A更新了数据,但还没有提交,这时事务B读取到事务A更新后的数据,然后事务A回滚了,此时事务B读取到的数据就是脏数据。(读取未遂)
  • 不可重复读。事务A对数据进行多次读取,事务B在事务A多次读取的过程中执行了更新并提交了。导致事务A多次读取到的数据并不一致。(更新骗人)
  • 幻读:事务A在读取数据后,事务B向事务A读取的数据中插入或删除数据,导致事务A再读的时候发现数据量不一致。(增减骗人)
  • 丢失修改。事务A和事务B对同一个数据修改,事务A先修改,事务B随后修改,事务B的修改覆盖了事务A的修改。(背后偷家)

4. 数据库的隔离级别

  • 未提交读。一个事务在提交前,它的修改对其他事务也是可见的
  • 提交读。一个事务在提交后,它的修改才能被其他事务看到
  • 可重复读。在同一个事务中多次读取到的数据是一致的
  • 串行化。需要加锁实现,会强制事务串行执行

数据库的隔离级别可以解决数据库的脏读、不可重复读、幻读等问题。

隔离级别脏读不可重读幻读
未提交读
提交读×
可重复读××
串行化×××

MySQL的默认隔离级别是可重复读。
大多数数据库系统默认提交读未隔离级别。

5. 事务的实现原理

事务是基于重做日志文件(redo log)和回滚日志(undo log)实现。

	redo log :事务中操作的任何数据,将最新的数据备份到一个地方。
	undo log :事务开始之前,在操作任何数据之前,首先将需要操作的数据备份。

具体区别

  • redo log 不是随事务的提交才写入的,而是在事务的执行过程中写入redo中。具体的落盘策略可以进行配置。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启MySQL服务的时候,根据redo log 进行重做,从而达到事务的未入磁盘数据进行持久化这一特性。
    redo log 实现事务的持久性。
  • undo log 用来回滚行记录到某个版本。事务未提交之前,undo
    保存了未提交之前的版本,undo中的数据可以作为数据旧版本快照提供其他并发事务进行快照读。是为了实现事务的原子性而出现的产物。
    undo log 实现事务的一致性。

实现原理

  • 每提交一个事务必须先将该事务的所有日志写入到重做日志文件进行持久化,数据库就可以通过重做日志保证事务的原子性和持久性。
  • 每当有修改事务时,还会产生undo log,如果需要回滚,则根据undo log 的反向语句进行逻辑操作,比如 insert 一条记录就 delete 一条记录。

6. 隔离级别如何实现(MVCC)

主要是靠锁和MVCC(多版本并发控制)实现,提交读和可重复读可以通过MVCC实现,串行化可以通过锁实现。

MVCC的实现,是通过保存数据在某个时间点的快照实现。根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。

对于InnoDB,聚簇索引记录中包含3个隐藏的列:

  • ROW ID:隐藏的ID,如果表没有主键,InnoDB会自动按ROW ID 产生一个聚集索引树。
  • 事务 ID:记录最后一次修改该记录的事务 ID。
  • 回滚指针:指向这条记录的上一个版本。

InnoDB的当前读和快照读:

  • 当前读:像select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)这些操作都是一种当前读,它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。
  • 快照读:简单的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于MVCC。可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本

数据库并发场景有三种:

  • 读-读:不存在任何问题,也不需要并发控制
  • 读-写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不可重复读
  • 写-写:有线程安全问题,可能会存在更新丢失问题

多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该session的数据库的快照。
所以MVCC可以为数据库解决以下问题:在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能。

举例理解
MVCC 事务ID 和 回滚 ID在表格修改过程中的变化

7. 什么是MySQL的 binlog。

MySQL的 binlog 是记录所有数据表结构变更(如create、alter table)以及表数据修改(insert、update、delete)的二进制日志文件。binlog 不会记录 select 和 show 等不会对数据做出修改的操作,但可以通过查询通用日志来查看 MySQL执行过的所有数据。

MySQL以事件形式记录,还包括语句所执行的消耗的时间,MySQL的二进制日志是事务安全性的,binlog 的主要目的是复制和恢复。

binlog 有三种格式,各有优缺点:

  • statement:基于SQL语句的模式,某些语句和函数如 UUID, LOAD DATE INFILE 等在赋值过程中可能导致数据不一致甚至出错。
  • row:基于行模式,记录行的变化,很安全。但记录日志会很大,在一些大表中清除大量数据时在 binlog 中会生成很多语句,可能导致从库延迟变大。
  • mixed:混合模式,根据语句选择以上两种模式
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值