1.MySQL工做流程
- 客户端发送请求到链接器(受权认证处理)
- 认证经过后:请求被转发到查询分析器(查询、解析、优化、缓存等等)
- 查询缓存中若是存在数据直接返回,不然将请求再次转发给优化器(存储过程、触发器、视图等等)
- 而后将请求转发给执行器调用存储引擎(存储和提取数据)
- 最终全部数据根据本地文件系统存储在磁盘(内存)上
2.ACID特性
- 事务:访问和更新数据库的执行单元,包含着一个或多个SQL语句
-
标准SQL事务须要知足的特性:html
- 原子性:事务是不可分割的最小执行单元,事务中的SQL语句只会所有执行成功或所有不执行
- 一致性:事务执行先后数据保持一致性,其余事务对同一个数据的访问结果是一致的
- 隔离性:并发访问数据库时,一个用户的事务不会被其余事务影响,并发事务之间是隔离的
- 持久性:事务被提交以后,发生任何状况,数据库中数据的改变是持久的
3.事务隔离级别
3-1.脏读/不可重复读/幻读
- 脏读:A事务可以读取其余事务的修改(update/delete/insert)操做
- 不可重复读:A事务可以读取其余事务已经提交的update/delete操做(同一条SQL查询读到不一样的结果)
- 幻读: A事务可以读取其余事务已经提交的insert操做(同一条SQL查询读到多余结果)
3-2.标准的事务隔离级别
- 未提交读:容许读取其余未提交事务的数据变动(存在脏读/不可重复读/幻读问题)
- 提交读(不可重复读):容许读取其余已提交事务的数据变动(还存在不可重复读/幻读问题)
- 可重复读:不容许读取其余已提交事务的数据变动(还存在幻读问题)
- 可串行化:全部操做串行化,读加读锁,写加写锁,读写锁互斥(解决幻读问题)
3-3.实验现象
A事务 |
B事务 |
begin; |
begin; |
update操做A记录的时候 |
delete/update操做A记录时会等待锁释放而超时;select操做A记录时看不到更改后的数据 |
commit(释放锁) |
|
|
delete/update操做A记录正常;select操做A记录时能看到更改后的数据 |
在RC级别下:当A事务进行update操做A记录时,为了并发操做过程当中的冲突,会给A记录加锁而且若是没有commit时,B事务delete/update操做都会超时,但解决脏读问题;当A事务提交后,select操做存在不可重复读问题;固然若是A事务进行insert操做,B事务很容易经过select操做读到多余记录,没有任何办法`算法
A事务 |
B事务 |
C事务 |
begin; |
begin; |
begin; |
select操做1:查询到A和B两条记录 |
|
|
|
update操做A记录 |
|
|
commit; |
|
|
|
insert操做C记录 |
|
|
commit; |
select操做1:同一条语句;没有读取到更新记录和插入记录 |
|
|
在INNODB存储引擎中的现象:同一条select查询读不到B事务的更新删除操做(由于读取的记录被加锁,其余事务没法执行更新删除操做),这样意味着解决了不可重读问题;也读取不到C事务添加操做,也解决了幻读问题(可是仅仅经过常规锁机制是没法阻止Insert操做的);因此在非INNODB存储引擎中都是采用串行化去解决幻读问题。`
- 以上是悲观锁的实现机制,可是为了减小开销,更多状况下会依赖于乐观锁的MVCC(多版本并发控制)来避免以上问题
4.多版本并发控制
4-1.悲观锁和乐观锁
- 悲观锁:假定大几率会发生并发更新冲突,访问和处理过程当中都会加排他锁,整个事务过程当中锁定数据,只有当事务提交或者回滚后才释放锁
- 乐观锁:假定大几率不会发生并发更新冲突,访问和处理数据过程当中不加锁,只在更新数据时再根据版本号和时间戳判断是否有冲突(版本号不一致),有则处理,无则提交事务
4-2.MVCC
5.当前读和快照读
- 当前读:即加锁读,读取记录的最新版本,会加锁保证其余并发事务不能修改当前记录,直至获取锁的事务释放锁
- 快照读:即不加锁读,读取记录的快照版本而非最新版本,经过MVCC实现
InnoDB默认的RR事务隔离级别下,不显式加『lock in share mode』与『for update』的『select』操做都属于快照读,保证事务执行过程当中只有第一次读以前提交的修改和本身的修改可见,其余的均不可见;但咱们读到的数据多是历史数据,是不及时的数据,不是数据库当前的数据!这在一些对于数据的时效特别敏感的业务中,就极可能出问题。
- 事务的隔离级别实际上都是定义了当前读的级别,MySQL为了减小锁处理(包括等待其它锁)的时间,提高并发能力,引入了快照读的概念,使得select不用加锁。而update、insert这些“当前读”,就须要另外的模块来解决了
6.锁机制
-
InnoDB主要实现了三种行锁算法:缓存
- Record Lock:记录锁,锁定一个行记录
- Gap Lock:间隙锁,锁定一个区间
- Next-key Lock:Record Lock+Gap Lock,锁定行记录+上下区间
- 不可重复读状况下:若是A事务select“当前读”操做(会给查询到的数据+记录锁),当B事务Insert新数据后,A事务再次执行相同条件的select“当前读”操做,是可能发现多余的数据,这就是“当前读”的幻读
- 可重复读状况下:若是A事务select“当前读”操做(会给查询到的记录+记录锁+间隙锁),当B事务Insert新数据后(若是在间隙空间中)会进行Waiting,此时A事务再次执行相同条件的select“当前读”操做, 是不可能发现多余的数据,这就解决了“当前读”的幻读问题。
- 间隙区间:根据不一样的索引类型(数据结构)范围性扫描的索引和记录而肯定的,若是没有Gap Lock,RR级别下是能够随意Insert的,从而致使“当前读”的幻读问题......
- 当前读下:行锁防止update/delete操做,GAP锁防止Insert操做,Next-Key锁解决了在RR级别下写数据时的幻读问题
- 我能够理解为:Gap锁解决一致性读问题;Next-Key锁解决一致性写问题吗?
参考