数据库复习

四大特性

  • 原子性:事务内包含的所有操作要么全部成功,要么全部失败回滚;实现:日志,将所有的更新操作全部写入日志当中,若因为一些系统奔溃/断电等原因导致事务中的部分更新操作已经执行,部分操作未执行,则通过回溯日志,将操作回滚,使系统保证原子性以及一致性;
  • 一致性:不管任何时间有少个并发的事务,系统也必须保持一致;
  • 隔离性:多个并发的事务的操作,在同一时间只能有一个事务执行(即串行的执行);
  • 持久性:事务正确执行后,事务中对数据的操作不会回滚;

四大隔离级别

  1. 读未提交(Read Uncommitted)
    此隔离级别容易出现数据的脏读(读到未提交的数据)。

  2. 读已提交(Read Committed)
    此隔离级别避免了脏读,但是会造成不可重复读。
    不可重复读:在一个事务内,多次读同一数据,在事务还没有结束时,另一个事务对该数据进行了修改,导致两次读到的数据不同。

  3. 可重复读(Repeatable Read)

此隔离级别避免了不可重复读,但可能会造成幻读。
幻读:在一个事务内,前后查询同一范围内的数据,发现前后两次查询的数据不一样。

  1. 可串行化(Serialzable)

最高的事务隔离级别,在此级别下,事务顺序执行,不仅可以避免脏读,不可重复读,还避免了幻读,但是,性能很低,代价高昂,一般很少使用。

MVCC原理

它的实现依赖于隐式字段、undo日志、快照读&当前读、Read View。

  1. 隐式字段

每一行记录都有两个隐藏列DB_TRX_ID、DB_ROLL_PTR,如果表中没有主键和非NULL唯一键时,则还会有第三个隐藏的主键列DB_ROW_ID。

  • DB_TRX_ID,记录每一行最近一次修改(修改/更新)它的事务ID,大小为6字节;
  • DB_ROLL_PTR,这个隐藏列就相当于一个指针,指向回滚段的undo日志,大小为7字节;
  • DB_ROW_ID,单调递增的行ID,大小为6字节;
  1. undo 日志
  • 事务未提交的时候,修改数据的镜像(修改前的旧版本),存到undo日志里。以便事务回滚时,恢复旧版本数据,撤销未提交事务数据对数据库的影响。
  • undo日志是逻辑日志。可以这样认为,当delete一条记录时,undo log中会记录一条对应的insert记录,当update一条记录时,它记录一条对应相反的update记录。
  • 存储undo日志的地方,就是回滚段。
  1. 快照读和当前读
  • 快照读:读取的是记录数据的可见版本(有旧的版本),不加锁,普通的select语句都是快照读。
  • 当前读:读取的是记录数据的最新版本,显示加锁的都是当前读。
  1. Read View

Read View就是事务执行快照读时,产生的读视图。
事务执行快照读时,会生成数据库系统当前的一个快照,记录当前系统中还有哪些活跃的读写事务,把它们放到一个列表里。
Read View主要是用来做可见性判断的,即判断当前事务可见哪个版本的数据~

  • m_ids:当前系统中那些活跃的读写事务ID,它数据结构为一个List。
  • min_limit_id:m_ids事务列表中,最小的事务ID
  • max_limit_id:m_ids事务列表中,最大的事务ID

如果DB_TRX_ID < min_limit_id,表明生成该版本的事务在生成ReadView前已经提交(因为事务ID是递增的),所以该版本可以被当前事务访问。
如果DB_TRX_ID > m_ids列表中最大的事务id,表明生成该版本的事务在生成ReadView后才生成,所以该版本不可以被当前事务访问。
如果 min_limit_id <= PDB_TRX_ID <= max_limit_id,需要判断m_ids.contains(DB_TRX_ID),如果在,则代表Read View生成时刻,这个事务还在活跃,还没有Commit,你修改的数据,当前事务也是看不见的;如果不在,则说明,你这个事务在Read View生成之前就已经Commit了,修改的结果,当前事务是能看见的。

mysql隔离级别的实现原理

  1. 读未提交

采取读不加锁原理。

  • 事务读不加锁,不阻塞其他事务的读和写
  • 事务写阻塞其他事务写,但不阻塞其他事务读;
  1. 已提交读
    已提交读就是在每次读数据的时候产生ReadView。
    参考这个链接
  2. 可重复读

可重复读就是在第一次读取数据的时候产生ReadView。

  1. 避免幻读

InnoDB避免幻读的方法就是在索引上加入Next-Key Locking。
5. 串行化

读加共享锁,写加排他锁,读写互斥。如果有未提交的事务正在修改某些行,所有select这些行的语句都会阻塞。