1.加锁的情况
数据库使用独占式*机制。在执行增删改语句时,会先进行锁表,直到commit或回滚。
如:A程序对表table1insert,还未commit时,B程序对表table1进行insert,此时会发生资源异常的情况,即锁表
锁表常发生于并发而不是并行。(并发在微观上并不是同时执行)
2.锁机制:
表级锁:
优点
-
实现逻辑简单,开销小。
-
获取锁和释放锁的速度快。
-
由于表级锁一次会将整个表锁定,所以能很好的避免死锁问题。
缺点
-
由于锁粒度最大,因此出现争用被锁定资源的概率也会最高,致使并发度十分低下
行级锁:
. 优点
-
由于锁粒度小,争用率低,并发高。
. 缺点
-
实现复杂,开销大。
-
加锁慢、容易出现死锁
页级锁:
开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
2.锁的种类
共享锁(行锁):多个事务对于同一数据可以共享一把锁。都能访问到数据,但不能修改。
排他锁(行锁):允许获取排他锁的事务更新数据,阻止其他事务取得相同的数据集共享读锁和排他写锁。
意向共享锁(表级锁):事务打算给数据行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
意向排他锁(表级锁):事务打算给数据行加排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
当前锁模式/是否兼容/请求锁模式 |
X |
IX |
S |
IS |
X |
冲突 |
冲突 |
冲突 |
冲突 |
IX |
冲突 |
兼容 |
冲突 |
兼容 |
S |
冲突 |
冲突 |
兼容 |
兼容 |
IS |
冲突 |
兼容 |
兼容 |
兼容 |
意向锁是InnoDB自动加的,不需用户干预。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及的数据集加排他锁(X);对于普通SELECT语句,InnoDB会自动给涉及数据集加共享锁(S);事务可以通过以下语句显式给记录集加共享锁或排锁。
共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE
用SELECT .. IN SHARE MODE获得共享锁,主要用在需要数据依存关系时确认某行记录是否存在,并确保没有人对这个记录进行UPDATE或者DELETE操作。但是如果当前事务也需要对该记录进行更新操作,则很有可能造成死锁,对于锁定行记录后需要进行更新操作的应用,应该使用SELECT ... FOR UPDATE方式获取排他锁。
3.分类依据:
按操作划分,可分为DML锁
、DDL锁
按加锁方式划分,可分为自动锁
、显示锁
DML锁(data locks,数据锁),用于保护数据的完整性,其中包括行级锁(Row Locks (TX锁))、表级锁(table lock(TM锁))。 DDL锁(dictionary locks,数据字典锁),用于保护数据库对象的结构,如表、索引等的结构定义。其中包排他DDL锁(Exclusive DDL lock)、共享DDL锁(Share DDL lock)、可中断解析锁(Breakable parse locks)
4.减少锁表的概率:
对于InnoDB表,主要有以下几点
(1)InnoDB的行销是基于索引实现的,如果不通过索引访问数据,InnoDB会使用表锁。
(2)InnoDB间隙锁机制,以及InnoDB使用间隙锁的原因。
(3)在不同的隔离级别下,InnoDB的锁机制和一致性读策略不同。
(4)MySQL的恢复和复制对InnoDB锁机制和一致性读策略也有较大影响。
(5)锁冲突甚至死锁很难完全避免。
在了解InnoDB的锁特性后,用户可以通过设计和SQL调整等措施减少锁冲突和死锁,包括:
-
尽量使用较低的隔离级别
-
精心设计索引,并尽量使用索引访问数据,使加锁更精确,从而减少锁冲突的机会。
-
选择合理的事务大小,小事务发生锁冲突的几率也更小。
-
给记录集显示加锁时,最好一次性请求足够级别的锁。比如要修改数据的话,最好直接申请排他锁,而不是先申请共享锁,修改时再请求排他锁,这样容易产生死锁。
-
减少insert 、update 、delete 语句执行 到 commite 之间的时间。如:批量执行改为单个执行、优化sql自身的非执行速度
-
如果异常则对事务进行回滚
-
不同的程序访问一组表时,应尽量约定以相同的顺序访问各表,对一个表而言,尽可能以固定的顺序存取表中的行。这样可以大减少死锁的机会。
-
尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响。
-
不要申请超过实际需要的锁级别;除非必须,查询时不要显示加锁。
-
对于一些特定的事务,可以使用表锁来提高处理速度或减少死锁的可能。
5.查看锁的征用次数:
行级锁:
mysql> show status like ‘InnoDB_row_lock%‘;
mysql> show status like ‘InnoDB_row_lock%‘;
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| InnoDB_row_lock_current_waits | 0 |
| InnoDB_row_lock_time | 0 |
| InnoDB_row_lock_time_avg | 0 |
| InnoDB_row_lock_time_max | 0 |
| InnoDB_row_lock_waits | 0 |
+-------------------------------+-------+
表级锁:
show status like ‘table%’;
一、按操作划分,可分为DML锁
、DDL锁
二、按锁的粒度划分,可分为表级锁
、行级锁
、页级锁
(mysql)
四、按加锁方式划分,可分为自动锁
、显示锁
DML锁(data locks,数据锁),用于保护数据的完整性,其中包括行级锁(Row Locks (TX锁))、表级锁(table lock(TM锁))。 DDL锁(dictionary locks,数据字典锁),用于保护数据库对象的结构,如表、索引等的结构定义。其中包排他DDL锁(Exclusive DDL lock)、共享DDL锁(Share DDL lock)、可中断解析锁(Breakable parse locks)