数据库加锁

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锁

按锁的粒度划分,可分为表级锁行级锁页级锁(mysql)

按锁级别划分,可分为共享锁排他锁

按加锁方式划分,可分为自动锁显示锁

按使用方式划分,可分为乐观锁悲观锁

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)

原文地址:https://www.cnblogs.com/lyqf/p/14364439.html