【数据库事务】ACID数据库四大特性理解

158 阅读5分钟

数据库事务ACID

四大特性介绍

1.什么是事务?

数据库的事务: 事务,简单理解就是一件完整的事情,有始有终!那么数据库事务,其实也就是对数据库的一系列操作组成的事件集合,这些事件要么同时成功,要么同时失败。比如:银行转账,A用户转给B用户,那么A用户金额减少,相应的B用户增加相应的金额,那么如果在A转出金额后,出现故障或者意外,那么B没收到钱,A的金额还减少了,这样就会造成部分金额丢失,为防止这种情况,引入了事务,事务的ACID四大特性:原子性、一致性、隔离性、持久性,便保障了这类事情的发生,保证数据的一致和持久。

下面以事务 Transaction(InnoDB引擎)为例!

2.原子性要么同时成功同时失败

原子性,就是操作的最小的粒度,也是多次相同操作所产生的影响或者结果一样,做到幂等性原则。

3.一致性事务操作前后,数据总量不变

一致性:是保证数据的前后访问一致。 一致性的实现依赖undo log! undo log

【机制】

  • 磁盘->段->区->页

    1. undo log存放在数据库内部的一个特殊段(segment)中,这个段称为undo段(undosegment);
    2. undo log是逻辑日志,因此只是将数据库逻辑恢复到原来的样子;
    3. undo log的另一个作用是MVCC,即在InnoDB存储引擎中MVCC的实现是通过undo来完成的;
    4. undo log的产生会伴随着redo log的产生,这是因为undo log也需要持久性的保护。

【与redo log区别】

  • redo log通常是物理日志,记录的是页的物理修改操作
  • undo log是逻辑日志,根据每行记录进行记录

3. 隔离性(Isolation) 多个事务之间。相互独立。

lock

【粒度】

  • 表锁、行锁

  • 【类型】

    1. S共享锁、X排他锁、IS意向共享、IX意向排他(排他锁x与一切不兼容,IX意向排他锁与共享、排他不兼容)
  • 【机制】

    1. 无锁:MVCC:对于正在更新的数据,InnoDB会去该行的一个快照数据(undo log)(历史版本数据,提交事务会存历史版本在log中)
    2. 加锁:X锁:SELECT ... FOR UPDATE

    ​ S锁:SELECT ...LOCK IN SHARE MODE

  • 【算法】

    • Record Lock:单个行记录上的锁,加在聚簇索引(mysql主键索引就是聚簇索引)
    • Gap Lock:间隙锁,锁定一个范围,但不包含记录本身
    • Next-Key Lock:Record+Gap,锁定一个范围,并锁本身
  • 【问题】

    • 读取
    - 脏读:某一个事务,读取了另一个事务未提交的数据
    - 不可重复度(虚读):某一事务,对同一数据前后读取结果不一致。
    - 幻读:某一事务,对同一个表前后查询到的行数不一致。
    • 更新(任何隔离级别都不会发生这类问题,因为对于DML操作需要先加IX锁,它会阻止事务2的行为
    - 第一类丢失更新:某一事务的回滚,导致另一事务已更新数据丢失
    - 第二类丢失更新:某一事务的提交,导致另一事务已更新数据丢失

【死锁】

  - 场景:

  - - 事务1:update ... where id=1;update ... where id=2;
    - 事务2:update ... where id=2;update ... where id=1;

  - 解决:

    - 超时回滚:`被动`innodb_lock_wait_timeout,当一个等待时间超过设置的某一阈值时,其中一个事务进行回滚,也就是释放锁(innodb是谁的范围大谁先释放)
    - 死锁检测:`主动`wait-for graph,采用等待图的方式来进行检测,这是更主动的死锁检测

【升级】

  - InnoDB存储引擎不存在锁升级问题( `因为其不是根据每个记录来产生行锁的,相反,其根据每个事务访问的每个页对锁进行管理的,采用的是位图的方式。因此不管一个事务锁住页中一个记录还是多个记录,其开销通常都是一致的`。 )
  • 隔离级别

    • Read Uncommitted读未提交
      • 未解决脏读、不可重复读、幻读问题
    • Read Committed读已提交
      • 采用Record Lock算法,解决脏读问题
      • 采用MVCC,总是读取被锁定行的最新一份快照数据。
    • Repeatable Read可重复读 (MySQL默认)
      • 默认的隔离级别
      • 采用Next-Key Lock算法,解决脏读、不可重复读、幻读问题
      • 采用MVCC,总是读取事务开始时的行历史版本数据
    • Serializable串行化
      • 解决了脏读、不可重复读、幻读问题(select ... LOCK IN SHARE MODE)

4. 持久性 (Durability) 当事务提交或回滚后,数据库会持久化的保存数据。

  • redo log

  • 【机制】

  - 当事务提交时,必须先将该事务的所有日志写入到Redo log进行持久化,待事务的COMMIT操作完成才算完成;
  - redo log是顺序写的,在数据库运行时不需要对该文件进行读取操作;
  - 每次写入redo log文件后,InnoDB引擎都需要调用一次fsnc(刷盘)操作;
  - redo log通常是物理日志,记录的是页的物理修改操作。

【与bin log区别】

  - redo log是在存储引擎层产生,bin log是在数据库的上层产生,并且bin log不仅仅针对InnoDB存储引擎,MySQL中任何存储引擎对于数据库的更改都会产生二进制日志;
  - bin log 是一种逻辑日志,其记录的是对应的SQL语句,而InnoDB引擎层面的redo log是物理格式日志,其记录的是对于每个页的修改;
  - bin log只在事务提交完成后进行一次写入,而redo log在事务进行中不断被写入,这表现为日志并不是随事务提交的顺序进行写入的。