面经总结(数据库)
DOC_ID // 2f215cONLINE

面经总结(数据库)

2025-4-7
UPDATED: 2026-1-24
技术
2703 CHARS
#操作系统#数据库#面试#硕士
CITRIO WHISPER
type
Post
status
Published
date
Apr 7, 2025
slug
summary
tags
操作系统
数据库
面试
硕士
category
技术
icon
password

数据库

事务的特性,如何保证

事务的特性是ACID,即原子性、一致性、隔离性、持久性。
原子性是指一个事务中的所有操作,要么全部完成,要么全都不完成。
一致性是指事务操作前后,数据满足完整性约束,不能出现我账户的钱减少而对方账户钱不增加的情况。
隔离性是指,数据库允许多个并发事务读写数据,需要隔离多个事务读写数据时的相互干扰。
持久性是指,数据库事务提交后,对数据的修改是永久的,即使系统故障也不会丢失。
原子性通过undo log回滚保证,在事务执行之前,数据库会记录操作前的数据状态到undo log,如果事务失败则根据undo log逆向操作,将数据恢复事务之前的状态。
一致性是由原子性隔离性和持久性保证的
隔离性可以通过锁机制和多版本并发控制保证。
持久性可以通过redo log保证。

undo log和redo log什么时候起作用

undo log用来保证事务的原子性,保证事务失败时可以通过undo log回滚到事务发生之前的状态。redo log用来保证事务的持久性,保证系统故障时可以根据redo log重放操作。 事务在commit之前不会落盘,因此这个阶段主要是根据undo log保证能够回滚。事务在commit之后保证落盘,这个阶段如果出问题就根据redo log重放操作。

事务的隔离级别

四个级别:读未提交、读已提交、可重复读、串行化
读未提交是一个事务的修改在提交之前就可以被其他事务看到。
读已提交是一个事务的修改只有在提交之后才能被其他事务看到。
可重复读是一个事务执行过程中看到的数据一直和事务启动时看到的数据是一致的。是innodb引擎的默认隔离级别
串行化是对记录加读写锁,多个事务通过读写锁访问数据。
脏读是指读取到其他事务还未提交的数据,这些数据是有可能回滚的。
不可重复读是一个事务多次读取同一个数据,但是前后读到的不一样。比如数据被其他事务提交,但是这个数据和本事务开始时看到的不一样
幻读是一个事务中满足查询记录的条目数量会因为其他事务提交数据而变化。
读未提交可能发生脏读、幻读、不可重复读
读已提交可能发生不可重复读和幻读
可重复读可能发生幻读
串行化不会发生这些现象。

可重复读的实现原理

在可重复读级别下,每个事务在第一次查询时会生成一个readview,后续的查询语句会利用read view找到开始查询时的数据,所以每次查询都是一样的。

可重复读不能解决幻读

事务的读取有快照读和当前读。快照读是普通的select语句,基于事务启动时的read view。当前读是select dor update、update或insert等显式要求读取最新数据或者可能修改数据的操作。
事务如果更新了其他事务插入的数据(虽然看不到),会导致更新快照,后续查询会包含新数据。
可以在开启事务后,马上执行当前读语句,这样会给记录加next key锁,避免其他事务插入新记录。

MVCC版本链实现、记录的可见性

读提交在每个select执行之前重新生成read view
可重复读在执行第一个select时生成一个read view,然后该事务都用这个read view
read view有4个字段,包括创建read view 的事务id,创建read view时当前数据库中未提交的事务id列表,创建readview时当前数据库中未提交的事务中最小事务的id,创建read view时当前数据库预留的下一个事务的id
innodb存储引擎的数据表记录中,每条记录会有隐藏列,包括事务id和指向旧版本记录的指针。指针的意思是说,每次改动记录时会将旧版本的记录写到undo日志中,这个指针就可以找到旧版本记录。
如果记录的事务id小于read view中未提交事务的最小id,就说明记录在创建read view之前已经提交,所以可见。
如果记录的事务id大于read view预留的下一个id,说明事务是在创建read view 之后创建,所以不可见。
如果记录的事务id在两者之间,则检查read view的未提交事务列表,如果在列表则说明未提交,所以不可见,如果不在则已经提交,所以(对读提交来说)可见

事务没有commit之前会不会持久化,为什么需要undo log

事务在commit之前,数据的持久化程度取决于redo log的刷盘策略。
在事务的运行过程中,mysql会把日志写到redo log buffer中,等到事务真正提交的时候,再将buffer中的内容写到redo log文件中。但是这个过程没有绕过page cache,也就是说提交的时候只是写到了pagecache,还需调用fsync保证落盘。
但是,在事务还未提交的时候,redolog也可能落盘,因为innodb有一个后台线程,会定期将redolog buffer中的日志写到pagecache,然后调用fsync持久化,因此事务没有commit也会部分落盘。并且其他事务提交时,可以设置将redo log buffer全部落盘,因此可能被带着持久化。第三种情况是事务的redo log buffer超过指定大小,这时候也需要写盘。
因为事务在未提交时候也可能部分落盘,所以需要undo log。

一条update是不是原子性的

update是原子性的,主要通过锁和undolog日志保证。执行update时会加行级锁,保证一个事务更新一条记录时不会被其他事务打扰。事务执行过程中会生成undolog,如果执行失败可以根据undolog回滚。

一个事务的语句特别多会怎样

为了保证事务的原子性和一致性需要加锁,如果语句过多会导致锁住太多数据,使得数据库性能下降,并可能会锁超时。其次需要保存的回滚记录太多占用空间。最后这个事务的执行时间长,会导致主从延迟(?)

mysql的锁

mysql中有全局锁、表级锁和行级锁。
全局锁会将整个数据库锁住,用于全库备份。
表级锁: • 表锁:lock tables 表名 read/write,read就是读锁(共享锁,其他线程只读),write就是写锁(独占锁,其他线程不能访问)。注意加锁之后在解锁之前本线程不允许访问其他表。表锁的颗粒度大,影响并发性能 • 元数据锁:这里的元数据是指的表结构,操作数据表时会自动加元数据锁。CRUD加读锁,更改表结构加写锁。注意这里写锁申请不到,会导致所有事务不能申请读锁。阻塞住 • 意向锁:当事务需要对某行加锁时,先申请表级的意向共享锁或者意向排他锁,这样其他事务可以快速判断该表中是否有行级锁,避免逐行扫描。比如一张表获取了行级独占锁,那么另一个事务就不能对这张表加锁。 • auto inc锁用于管理表内的自增列,保证自增字段的唯一性和连续性。auto inc锁是插入语句执行完就释放,而不是等待事务结束再释放。还有一种更轻量的自增锁,将自增字段赋值之后就释放了,而不是等到插入语句完成。
行级锁:innodb引擎支持,myisam不支持,需要先加表级意向锁避免逐行扫描 • 记录锁: ◦ 锁住的是记录,可以有共享和独占两种。一个事务对一行加共享锁后,其他事务还可以对这一行加共享锁,但是不能加独占锁。如果加了独占锁,其他事务不能对这行加锁。 • 间隙锁 ◦ 间隙锁是在可重复读级别下引入的一种行级锁,锁定的是一个区间而不是具体的记录。加锁之后不能对区间中做插入操作,从而避免幻读。 • next key锁 ◦ 结合了记录锁和间隙锁,既能锁定记录本身不被修改,又不允许在范围内插入记录。
  1. Level DB
  1. join table 实现方式
  1. 数据库如何处理null
  1. 数据库如何判断事务的可见性 • 数据库存储引擎格式 • B+树上数据记录1 1 1,一个操作将其更新为 1 2 2,如何操作? ◦ 记录日志 • mysql中事务A读 1 1 1,另一个事务B将其update为1 2 2,但没有提交,那么当前处理器,B+树中存了哪些数据,页面的值是什么,哪些信息发生了变化 • 版本号存在哪里,如何组织 • RocksDB • 主键索引和联合索引的区别 • 主键索引在索引表上只存有索引数据吗
NAVIGATION // Related Articles
Loading...