1 锁概念
1.1 什么是锁?
相必从事软件相关工作的各位同学,都或多或少的听过锁的概念,那么锁究竟是用来干什么的呢?
锁其实就是计算机用来协调多个进程或者线程并发访问某一资源的一种机制。
如果不加锁的话,大家一起操作某一共享资源,就会引起混乱。加锁是为了让并行操作变成串行操作,当某一进程或者线程操作资源的时候,我们用一把锁将后边的进程或者是线程拦截起来,防止他们干扰操作。当这一线程操作完毕之后,我们放行下一个线程对资源进行操作,这样互不影响有条不紊,极大的保证资源的安全性。
1.2 数据库中的锁?
数据库中的锁很好理解,数据就是一种共享资源,拥有操作权限的各个用户都可以操作数据。如果两个线程同时去修改数据库的某一个数据,比如库存,如果不加锁的话两个线程同时扣减库存,原来库存100,小明扣减10个库存,小红扣减5个,如果没有锁的控制,他们都是对100进行修改,那么结果就是90或者95,但是他俩一共扣了15个,正常库存是85才对。
如果不加锁的话,数据的一致性就没法得到保障。
1.3 MySQL中的锁
MySQL数据库是众多数据库中的一种,随着去IOE化的发展,已及MySQL数据库本身的各种优势,MySQL数据库已经成为各大企业结构化数据库的首选,所以本篇文章我们大量篇幅讲MySQL的锁。
1.3.1 锁的级别
MySQL中的锁级别其实是取决于我们使用哪种存储引擎,不同的存储引擎锁也是有所区别
MyISAM和MEMORY存储引擎
- 表级锁(table-level locking);
BDB存储引擎
- 页面锁(page-level locking);
- 表级锁(table-level locking);
InnoDB存储引擎
- 行级锁(row-level locking),默认;
- 表级锁(table-level locking);
MySQL中不同锁级别的区别:
- 表级锁: 开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
表级锁更适合于以查询为主,只有少量按索引条件更新数据的场景;
- 行级锁: 开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的场景。
- 页面锁: 开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般 .
由于我们常用的存储引擎一般为InnoDB或者MyISAM,所以页面锁很少遇到
1.3.2 读写锁
上边所讲述的只是锁的级别,数据库真正使用的是读锁,或者写锁。每个级别的锁都分为读锁,或者写锁。
2 表级锁与行级锁
这里的表锁指代MyISAM的表级锁,行锁指代InnoDB的行级锁,他们是我们最常用的,所以以他们为例进行介绍。
2.1 表锁
表共享读锁(Table Read Lock)
读锁不会阻塞其他用户的读操作,但是会阻塞写操作。
如何加锁?
查询操作(SELECT)会自动加读锁。
表独占写锁(Table Write Lock)
写锁会阻塞其他用户对同一表的读和写操作。
执行更新操作 (UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁
2.2 行锁
InnoDB与MyISAM的最大不同有两点:一是支持事务;二是使用行级锁。事务的加入让锁变的更为复杂,带入了不少新的问题。InnoDB的行锁是基于索引实现的,如果不通过索引访问数据,InnoDB会使用表锁。
共享锁(S):又称读锁。
读锁不会阻塞其他事务的读,但是会阻塞其他事务写,不影响其它事务获取该事物的读锁。
读锁允许一个事务去读一行数据,并且阻止其他事务获得相同数据集的写锁。但是其他事务可以继续获得当前事务的读书,直到所有的读锁释放,才可以允许其他事务获取该数据集的写锁。
查询操作(SELECT)不会加任何锁。 使用select … lock in share mode语句加共享锁。
只要有事务读该行数据,就不能有事务进行写操作。
排他锁(X):又称写锁。
获取写锁的事务,可以更新数据,会阻塞其他事务获取该数据的读锁和写锁。
执行更新操作 (UPDATE、DELETE、INSERT等)都会自动给涉及到的数据加上排他锁。
使用select …for update语句加排他锁。
意向共享锁(IS):
事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
意向排他锁(IX):
事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
不同情景使用不同算法实现的锁:
- next KeyLocks锁,同时锁住记录(数据),并且锁住记录前后的间隙(Gap)
- 间隙(Gap)锁,不锁记录,仅仅记录前后的间隙(Gap)
- Recordlock锁(锁数据,不锁Gap)
所以其实 Next-KeyLocks=Gap锁+ Recordlock锁