一、数据库系统管理
ACID,是指数据库管理系统(DBMS)在写入或更新资料的过程中,为保证事务(transaction)是正确可靠的,所必须具备的四个特性:原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)。
在数据库系统中,一个事务是指:由一系列数据库操作组成的一个完整的逻辑过程。例如银行转帐,从原账户扣除金额,以及向目标账户添加金额,这两个数据库操作的总和,构成一个完整的逻辑过程,不可拆分。这个过程被称为一个事务,具有ACID特性
一、事务
概念
事务是指满足ACID特性的一组操作,可以通过Commit提交一个事务,也可使用Rollback进行回滚。
ACID
1.原子性(Atomicity)
事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。
回滚可以用回滚日志(Undo log)来实现,回滚日志记录着事务所执行的修改操作,在回滚时反向执行这些修改操作即可。
2.一致性(Consistency)
数据库在事务执行前后都保持一致性状态。在一致性状态下,所有事务对同一个数据的读取结果都是相同的。
3.隔离性(Isolation)
一个事务所做的修改在最终提交以前,对其他事务是不可见的。
4.持久性(Durability)
一旦事务提交,则其所做的修改将会永久保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失。
系统发生崩溃可以重做日志(Redo log)进行恢复,从而实现持久性。与回滚日志记录数据的逻辑修改不同,重做日志记录的是数据页的物理修改。
二、并发一致性问题
在并发环境下,事务的隔离性很难保证,因此会出现很多并发一致性问题。
丢失修改
丢失修改指一个事务的更新操作被另一个事务的更新操作替换。一般在现实生活中常会遇到,例如:T1 和 T2 两个事务都对一个数据进行修改,T1 先修改并提交生效,T2 随后修改,T2 的修改覆盖了 T1 的修改。
读脏数据
读脏数据指在不同的事务下,当前事务可以读到另外事务未提交的数据。例如:T1 修改一个数据但未提交,T2 随后读取这个数据。如果 T1 撤销了这次修改,那么 T2 读取的数据是脏数据。
不可重复读
指在一个事务哪多次读取统一数据集合。
幻影读
也属于不可重复读的情况,T1 读取某个范围的数据,T2 在这个范围内插入新的数据,T1 再次读取这个范围的数据,此时读取的结果和和第一次读取的结果不同。
三、封锁
封锁粒度
mysql提供了两种封锁粒度:行级锁和表级锁
「表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高;
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
适用:从锁的角度来说,表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用;而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统。」
应该尽量只锁定需要修改的那部分数据,而不是所有的资源。锁定的数据量越少,发生锁争用的可能就越小,系统的并发程度就越高。
封锁类型
1.读写锁
互斥锁(Exclusive),简写为X锁,写锁
共享锁(Shared),S锁,读锁
有以下两个规定:
一个事务对对数据对象A加了X锁,就可以对A进行读取和更新。加
2.意向锁
使用意向锁(Intension locks)可以更容易地支持多粒度封锁。
x:写锁
s:读锁
IX:表锁
IS:表锁
封锁协议
1.三级封锁协议
一级封锁协议
二级封锁协议
三级封锁协议
2.两段锁协议
加锁和解锁分为两个阶段进行。
MySQL隐式锁定与显式锁定
四、隔离级别
未提交读(read uncommitted)
事务中的修改,即使没有提交,对其它食物也是可见的。
提交读(read committed)
一个事务只能读取已提交的事务所做的修改。一个事务所做的修改在提交之前对其它事务是不可见的。
可重复读(repeatable read)
保证在同一个事务中多次读取统一数据的结果是一样的。
可串行化(serializable)
强制事务串行执行,这样多个事务互不干扰,不会出现并发一致性问题。
该隔离级别需要加锁实现,因为需要使用加锁机制保证同一时间只有一个事务执行,也就是保证事务串行执行。
五、多版本并发控制
多版本并发控制(Multi-Version Concurrency Control,MVCC)是MySQ L的InnoDB存储引擎实现隔离级别的一种具体方式,用于实现提交读和可重复读这两种隔离级别。而未提交读隔离级别总是读取最新的数据行,央求很低,无需使用MVCC。可串行化隔离级别需要对所有读取的行都加锁,单纯使用MVCC无法实现。
基本思想
在封锁一节中提到,加锁能解决多个事务同时执行时出现的并发一致性问题。在实际场景中读操作往往多于写操作,因此又引入了读写锁来避免不必要的加锁操作,例如读和读没有互斥关系。读写锁中读和写操作仍然是互斥的,而MVCC利用了多版本思想,写操作更新最新的版本快照,而读操作去读旧版本快照,没有互斥关系,这一点和copyonwrite类似。
在多版本控制MVCC中事务的修改操作(delete\insert\update)会为数据行新增一个版本快照。
脏读和不可重复读最根本的原因是事务读取到其他事务未提交的修改。在事务进行读取操作时,为了解决脏读和不可重复读问题,MVCC规定只能读取已经提交的快照。当然一个事务可以读取自身未提交的快照,这不算脏读。
版本号
系统版本号SYS_ID:是一个递增的数字,每开始一个新的事务,系统版本号就会自动递增。
事务版本号TRX_ID:事务开始时的系统版本号。
Undo日志
MVCC的多版本指的是多个版本的快照,快照存储在Undo日志中,该日志通过会滚指针ROll_PTR把一个数据行的所有快照连接起来。
例如在MYSQL