数据库事务

事务是指满足AICD特性的一组操作,通过commit来提交事务,也可以通过RollBack来进行事务回滚。

AICD

  • 原子性(Atomicity)
    事务被视为不可分割的最小单位,要么成功,要么失败。
  • 一致性(Consistency)
    数据库在执行事务前后保持一致性,所有事务对一个数据读取结果都是相同的。
  • 隔离性(Isolation)
    一个事务所做修改,在提交之前是对其他事务不可见的。
  • 持久性(Durability)
    一旦事务提交,则永久存在数据库中。

  • 满足一致性,执行结果才是一样的。
  • 满足隔离型和原子性,就一定满足一致性。
  • 持久性是将数据持久化,放置数据库崩溃导致数据丢失。

AutoCommit

在MySQL中,默认采用自动提交模式。只要不显式使用START TRANSACTION语句开始一个事务,每个查询都会当做一个事务自动提交。

数据库并发一致性

在并发环境下,事务隔离性很难保证,因此会出现并发一致性的问题。

丢失修改

两个事务对同一个数据进行修改,后修改的事务会覆盖先修改的事务。

读脏数据

同一个数据,一个事务修改后,另一个事务读取,第一个事务在撤销修改,则第二个事务读取的就是脏数据。

不可重复度

第一个事务读取了数据后,第二个失误对该数据进行修改,此时第一个数据再去读取数据,两次读取结果就不一致。

幻影读

第一个事务读取了一个范围的数据,第二个事务在这个范围内插入数据,此时第一个事务在读取,两次读取结果不一致。

原因与解决

  • 并发情况下破坏了事务的隔离性
  • 可以通过并发控制来保证事务隔离性
  • 可以通过封锁方式保证事务隔离性
  • 可以通过事务隔离级别来进行事务隔离性

封锁

用户可以通过封锁来控制并发控制,但是封锁操作需要用户控制,比较复杂。

封锁粒度

  • 行级锁
  • 表级锁

封锁类型

读写锁

  • 互斥锁 - X 锁 - 写锁
  • 共享锁 - S 锁 - 读锁

  • 一个事务对数据加了X锁,就可对数据进行读取和更新,其他事务不能对A加任何所。
  • 一个事务对数据加了S锁,就可对数据进行读取,但不能进行更新。加锁期间,其他事务可以对数据加S锁,但不能加X锁。

意向锁

在存在行级锁和表级所时,事务想对表加锁,则要判断表中所有行是否加锁。十分耗时。因此引入意向锁:IS/IX,意向锁是表级锁。他用来表示该表中,有事务对行数据加了锁。

  • 一个事务要获取数据的S锁,则要获取表的IS锁或更强的锁。
  • 一个事务要获取数据的X锁,则要获取表的IX锁。

封锁协议

三级封锁协议

一级封锁协议

事务修改数据时必须加X锁,事务结束释放。

解决丢失修改问题,两个事务不能同时修改一个数据。

二级封锁协议

在一级基础上,要求事务读数据时加S锁,读完释放。

解决读脏数据的问题,当有事务对数据修改时加X锁,此时数据无法加S锁读取。

三级封锁协议

在二级基础上,要求读取数据时必须加S锁,事务结束后释放。

可以解决不可重复读的问题,事务读取数据时,其他事务不能对数据加X锁修改。

两段封锁协议

加锁和解锁在两个阶段执行

MySQL隐式与显示锁定

隐式锁定

Mysql 的 InnoDB存储引擎采用两段锁协议,会根据隔离级别在需要的时候自动加锁,并且所有的锁在同一时刻(执行commit和rollback时)被释放。

显式锁定

InnoDb会根据事务的隔离级别在需要的时候自动加锁,InnoDb也可以通过特定的语句进行显式锁定(不属于SQL规范)

SELECT ... LOCK In SHARE MODE;
SELECT ... FOR UPDATE;

事务隔离级别

未提交读

事务中的修改,即使没有提交,对其他事务也是可见的。

提交读

与未提交读相反,事务的修改,没有提交,对其他事务是不可见的。

可重复读

保证在同一个事务中的多次读取同一数据结果是一样的。

可串行化

强制事务串行执行,多个事务互不干扰。需要通过加锁实现,锁机制保证同一时间只有一个事务执行,也就保证了事务串行。

多版本并发控制 - MVCC

多版本并发控制是MySQL的InnoDb存储引擎实现隔离级别的具体方式。
实现:

  • 提交读
  • 可重复读。

  • 未提交读总是读取最新的数据行,无需使用MVCC
  • 可串行化需要对读取的行加锁,单使用MVCC无法实现。

存储引擎

数据库存储是数据库底层软件组织,用于为数据库提供增、删、查、改等操作。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能。Mysql的核心就是存储引擎

可以通过SHOW ENGINES来查询数据库的存储引擎,Mysql默认的存储引擎是InnoDB

InnoDB

InnoDB是事务型数据库的首选引擎,支持行锁定和外键。

  • 支持事务、行锁、表锁、外键。
  • 5.6.4之前不支持全文索引,5.6.4开始支持全文索引。
  • 主键索引是聚集索引。
  • 默认使用B+Tree,叶子节点存放了主键和行记录。也有Hash索引和全文索引。

名词解释:

  • 全文索引:先创建索引,再对索引进行搜索。
  • 聚集索引:数据行的物理顺序与列值的逻辑顺序相同,即一块地址内存中,物理地址在前面的那行数据,在表中也在前面。

Next-Key Locks

Next-Key Locks是MySQL中InnoDB存储引擎的一种锁实现。
Next-Key Locks是Record Locks和Gap Locks的结合,不仅锁定索引,也锁定索引之间的间隙。

  • Record Lock : 锁定记录索引,而不是记录本身。如果表没有索引,则会在主键上自动创建隐藏索引
  • Gap Lock : 锁定索引之间的间隙,而不是索引本身

MyISAM

  • 不支持事务,外键。在Web、数据仓储环境下常用。
  • 插入、查询速度较高。
  • 支持所表,支持全文索引
  • 并发性能差,崩溃后无法恢复
  • 主键是非聚集索引,叶子节点值存储主键和对应数据地址

Memory

  • 内存存储,使用Hash索引,数据不经过磁盘IO,速度最快。
  • 一般用于存储保存中间结果数据

总结

  1. 数据库事务是满足AICD特性的一组数据库操作。
  2. 并发情况由于不能满足AICD会出现的问题(4种):
    1. 丢失修改
    2. 读脏数据
    3. 不能重复读
    4. 幻影读
  3. 如何在并发情况下满足AICD(两种):
    1. 封锁(开销大):
      1. 封锁类型(2种):
        1. 读写锁 S/X锁
        2. 意向锁 IS/IX锁
      2. 封锁协议(2类)
        1. 三级封锁协议
        2. 两段封锁协议
    2. 事务隔离(常用,4种)
      1. 未提交读
      2. 提交读
      3. 可重复读
      4. 可串行化
  4. 数据库引擎 -> 常用的数据库引擎(3种):
    1. InnoDB -> MySQL默认引擎,支持外键、事务、锁、索引
    2. MyISAM -> 不支持外键、事务,只有表锁,支持全文索引
    3. Memory -> 内存存储,Hash索引,速度快