MySQL技术内幕InnoDB存储引擎学习笔记(第六章)

来源:互联网 发布:cp1200写频软件下载 编辑:程序博客网 时间:2024/05/17 21:49

                       第六章 锁

一、实验环境

宿主机系统:windows7

虚拟机:OracleVMVirtualBox

Linux:ubuntukylin-14.04.1-amd64.iso

jdk:1.7.0_101

mysql:5.7.12

书上的mysql版本:5.6.6

二、什么是锁

锁是数据库熊区别于文件系统的一个关键特性。锁机制用于管理对共享资源的并发访问,提供数据的完整性和一致性。

不同数据库对锁的实现也不同。

innoDB锁的实现和oracle类似,提供一致性的非锁定读、行级锁支持。航迹锁没有相关额外的开销,并可以同时得到并发性和一致性。

三、lock和latch

latch:闩锁(轻量级锁),要求锁定的时间必须非常短。若时间长,则性能差。

innodb中可分为:mutex(互斥锁)、rwlock(读写锁)。目的是保证并发线程操作临界资源的正确性,通常没有死锁检测机制。

show engine innodb mutex

lock:对象是事务,用来锁定数据库中的对象,如表,页,行。并且一般lock的对象仅在事务commit或rollback后进行释放。有死锁机制。

三、innodb中的锁

共享锁(S Lock):允许事务读一行数据

排它锁(XLock):允许事务删除或更新一行数据

一致性非锁定读:通过行多版本控制的方式来读取当前执行时间数据库中行的数据。如果所读取的行正在进行update或delete操作,这是读取操作不会因此去等待行上X锁的释放,而是会读取行的快照,通过undo段来完成。

read committed事务隔离级别,总是读取行的最新版本,如果行被锁定,则读取该行版本的最新快照。

replication read 事务隔离级别,总是读取事务开始时的行数据。

一致性锁定读

select ... for update:对读取的行加一个X锁。

select ... lock in share mode:对读取的行加一个S锁。

事务提交后,锁释放。

自增长与锁

得到自增长计数器的值:select max(auto_inc_col) from  t forupdate;

锁不是在事务完成后释放,而是完成对自增长值插入的SQL语句后立即释放。

insert ...select 大数据量插入会影响性能。

重要参数:innodb_autoinc_lock_mode来控制自增长模式。可选值0,1,2

外键和锁

如果没有显式的给外键列加索引,innodb会自动给其加一个索引。可以避免表锁。

外键的插入或者更新,首先要查询父表中的记录,采用的是select ... lock in share mode 主动对父表加一个S锁。如果父表已加X锁,则子表上的操作会被阻塞。

锁的算法

行锁的三种算法:

record lock:单个行记录上的锁。会去锁住索引记录,如果没有设置索引,innodb会使用隐式主键来进行锁定。

 

gap lock:间隙锁,锁定一个范围,但是不包含记录本身。阻止多个事务将记录插入到同一范围内。

next-key lock :锁定一个范围,且锁定记录本身,是前两种相加。对于行的查询,采用此算法

默认的事务隔离级别即repeatable read 下,采用next-keylocking 来避免phantom problem(幻像问题即不可重复读)。即:在同一事务下,连续执行两次同样的sql语句可能导致不同的结果,第二次的sql语句可能会返回之前不存在的行。

锁问题(3个)

1.脏读:指的是在不同的事务下,当前事务可以读到另外事务未提交的数据,即可以读到脏数据。

脏数据:事务对缓冲池中行记录的修改,还未提交。

脏读发生的条件是:需要事务的隔离级别为read uncommitted。

2.不可重复读:在一个事务内多次读取同一数据集合。这个事务未结束时,另外一个事务页访问该同一数据集合,并做了DML操作。这样,在一个事务内两次读到的数据不一样。

与脏读的区别:脏读读到的是未提交的数据,不可重复读,读到的是已经提交的数据。

不可重复读发生的条件:事务隔离级别为read committed。

innoDB的默认事务隔离级别是read repeatable 采用next-key lock算法,避免了不可重复读现象。

3.丢失更新:

一个事务的更新会被另外一个事务的更新操作锁覆盖,导致数据不一致。

在当前数据库任何隔离级别下,都不会导致丢失更新的问题。但是逻辑意义上有可能。

1)事务T1查询一行数据,放入本地内存,并显示给一个终端用户User1

2)事务T2查询一行数据,放入本地内存,并显示给一个终端用户User2

3)User1修改这行记录,并提交。

4)User2修改这行记录,并提交。

如此,User1提交的更新操作丢失了。

要避免该问题发生,需让事务在这种情况下的操作变成串行化,而不是并行操作。

步骤1中,对用户读取的记录加上一个排他X锁(select ... for update),步骤2也加X锁(select ... for update),则必须等到步骤3完成后才能完成步骤4.

阻塞:一个事务中的锁需要等待另一个事务中的锁释放它所占的资源,就是阻塞。

参数:innodb_lock_wai_timeout来控制等待时间。 动态参数

参数:innodb_rollback_on_timeout是否在等待超时时执行回滚操作,默认为off代表不回滚。静态参数。

死锁: 两个或两个以上的事务在执行的过程中,因为夺锁资源而造成的一种互相等待的现象。

解决方法,不要有等待,则1、回滚,2超时。

innodb采用主动的死锁检测方式:wait-for-graph(等待图)

0 0
原创粉丝点击