数据库锁分类

数据库锁
锁和索引是数据库两大核心概念 , 了解索引 , 可以从 B+ 树 , Hash 索引 , 页结构 , 缓存池 , 索引原则等方面理解 。理解锁 , 要从哪些方面入手?
为什么要加锁加锁的目的 , 其实是为了保证数据的一致性 。当多个线程并发访问某个数据时 , 加锁 , 可以保证这个数据在任何时刻最多只有一个线程在访问 , 保证数据的完整性和一致性 。
锁的分类锁可以按照锁粒度划分 , 可以按照数据库管理角度划分 。
按照锁粒度划分按照锁粒度划分 , 可以将锁划分成 行锁 , 页锁和表锁 。
快速回忆一遍 InnoDB 存储引擎的逻辑结构:所有数据都被逻辑地存放在一个空间内 , 称为表空间 , 而表空间由段(sengment)、区(extent)、页(page)组成 。

数据库锁分类

文章插图
 
InnoDB存储引擎的逻辑结构
  1. 行锁
行锁 , 就是按照行的粒度对数据进行锁定 , 锁定粒度小 , 发生锁冲突概率低 , 可以实现并发都高 , 但是对于锁的开销比较大 , 加上会比较慢 , 容易出现死锁的情况 。
  1. 页锁
页锁就是页的粒度上进行锁定 , 锁定的数据资源比行锁要多 , 因为一个页中可以有多个行记录 , 当我们使用页锁的时候 , 会出现数据浪费的现象 , 页锁的开销介于表锁行锁之间 。
  1. 表锁
表锁就是对数据进行锁定 , 锁定粒度很大 , 发送锁的概率很高 , 数据访问的并发度 。不过好处在于对锁的使用开销小 , 加锁会很快 。
【数据库锁分类】InnoDB 和 Oracle 支持行锁和表锁 , MyISAM 只支持表锁 ,  MySQL BDB 存储引擎支持页锁和表锁 。SQL Server 可以支持行锁 , 页锁和表锁 。
数据库锁分类

文章插图
 
image
按照数据库管理角度划分按照数据库管理角度划分 , 可以将锁分成排他锁和共享锁 。
  1. 共享锁
共享锁 , 也叫读锁 , 或者 S 锁 , 共享锁锁定的资源可以被其他用户读取 , 但不能修改 。在进行 SElECT 的时候 , 会将对象进行共享锁锁定 , 当数据读取完毕之后 , 就会释放共享锁 , 这样就可以保证数据在读取时不被修改 。
给某个表加共享锁:
LOCK TABLE product_comment READ;当数据表加上共享锁的时候 , 该表数据就会变成只读模式 , 当时我们想更新 product_comment 表中的数据会报错 , 比如:
UPDATE product_comment SET product_id = 10002 WHERE user_id = 912178;系统报错如下:
ERROR 1099 (HY000): Table 'product_comment' was locked with a READ lock and can't be updated如果对表共享锁进行解锁:
UNLOCK TABLE;给某行数据加共享锁
SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE例子:
SELECT comment_id, product_id, comment_text, user_id FROM product_comment WHERE user_id = 912178 LOCK IN SHARE MODE
  1. 排他锁
排他锁也叫做独占锁 , 写锁或者 X 锁 , 排他锁锁定的数据只允许进行锁定操作的事务使用 , 其他事务无法对已锁定的数据进行查询或者修改 。
给表加排他锁
LOCK TABLE product_comment WRITE;排他锁的事务可以对 product_comment 进行查询和修改 。其他事务如果想要在 product_comment 表上查询数据 , 则需要等待 。
释放掉排他锁
UNLOCK TABLE;数据行上添加排他锁
SELECT * FROM table_name WHERE ... FOR UPDATE例子:
SELECT comment_id, product_id, comment_text, user_id FROM product_comment WHERE user_id = 912178 FOR UPDATE;当我们对数据进行更新的时候会自动使用排他锁 , 也就是 INSERT  , DELETE 或者 UPDATE 的时候 , 数据库自动使用排他锁 , 防止其他事务对改数据进行操作 。
从程序员角度进行划分
  1. 乐观锁
乐观锁认为对同一个数据并发操作不会总发生 , 是小概率事件 , 因此不用每次对数据进行更新或者删除 。


推荐阅读