In-depth understanding of the transaction and the lock mechanism (under)

MySQL lock Category

 

Previously mentioned the lock, the following will explain in detail the MySQL locks, we take a look at the classification locks, there are three levels of locking in MySQL: page-level locking, table-level locking, row-level locking.

  • Table-level lock: Small overhead, lock fast; not deadlock; lock large size, the probability of lock conflicts of the highest and lowest degree of concurrency. It will happen: MyISAM, memory, InnoDB, BDB storage engine and so on.

  • Row-level locking: large overhead, locking slow; there will be a deadlock; locking granularity smallest and lowest probability of lock conflicts, the highest degree of concurrency. It will happen: InnoDB storage engine.

  • Page-level locking: locking overhead and time boundaries between the table and row locks; there will be a deadlock; locking granularity boundary between the table and row locks, concurrency in general. It will happen: BDB storage engine.

Three levels respectively corresponding to the storage engine lock relationship as shown in FIG.

 

 

Note: MySQL tables include lock read and write locks. Just remember this table lock mode is compatible matrix can be.

The locks InnoDB

In the MySQL InnoDB storage engine, lock into the row and table locks. Wherein the lock comprises two locking row.

  • Shared lock (S): allows a transaction to read a row to prevent other transactions to obtain the same data set exclusive lock.

  • Exclusive lock (X): to allow him to acquire an exclusive lock transaction update data, preventing other transactions made to share the same data set read locks and exclusive write locks.

Further, in order to allow the coexistence of rows and table locks, multi-granularity locking mechanism, InnoDB there intent lock (Intention Locks) two kinds of internal use, are both intent lock table lock. Table lock is divided into three.

  • Intention shared lock (IS): Transaction plans to add rows of data rows shared lock before the transaction to a data line shared locks must obtain the IS lock on the table.

  • Intent exclusive locks (IX): Rights intends to add to the data line row exclusive lock, the transaction must be obtained before his lock IX lock on the table to add a row of data rows.

  • Lock increment (AUTO-INC Locks): Special table lock, since an increase of the counter to obtain the maximum count value by the counter sub-growth "lock."

We must get the table level intent lock before adding row lock, or wait innodb_lock_wait_timeout timeout to decide whether to roll back the transaction according to innodb_rollback_on_timeout.

InnoDB increase self-locking

In the MySQL InnoDB storage engine, we design table structure, I usually recommend adding an increment as the primary key. Here it will involve a special locking: locking increment (i.e.: AUTO-INC Locks), which belongs to a table lock is released immediately after the INSERT. We can perform the show engine innodb status \ G to view the increment lock status information.

 

Increase in self-locking of course, there is a core parameters, need to focus on that innodb_autoinc_lock_mode, it has three values ​​0,1,2. Keep the default on the line. Specific meaning can refer to the official document, it will not be repeated here, as shown below.

 

 InnoDB locking relationship matrix as shown below, where: + indicates compatible, - indicates not compatible.

 

 

InnoDB row lock

 

InnoDB row lock is obtained by recording the index on a data page (Record) to achieve locking. There are three main algorithm: Record Lock, Gap Lock and Next-key Lock.

  • Record Lock locks: locks of the individual rows (lock data, not locked Gap).

  • Gap Lock Lock: gap lock, a lock range, excluding (GAP not lock data, only the front latch data) record itself.

  • Next-key Lock locks: lock the data at the same time, the previous data and lock Gap.

InnoDB lock troubleshoot problems

InnoDB lock troubleshoot problems usually have two methods.

  • After opening innodb_lock_monitor table, remember to pay attention to the use of closed, otherwise it will affect performance.

  • After MySQL 5.5 version, you can view the library information_schema below innodb_locks, innodb_lock_waits, innodb_trx lock troubleshoot problems three views of InnoDB.

InnoDB locking behavior

Analysis of different locking behavior of InnoDB index below give some examples. Need to be linked with the lock isolation level analysis, we RR, for example, is to analyze the four scenes.

  • Primary + RR.

  • The only key + RR.

  • Non-unique keys + RR.

  • No index + RR.

The following explains a first case: a primary key + RR, as shown below.

 

 

Assumptions are:

  • update t1 set name=‘XX’ where id=10。

  • id 为主键索引。

加锁行为:仅在 id=10 的主键索引记录上加 X锁。

 

第二种情况:唯一键 + RR,如下图所示。

 

 

假设条件是:

  • update t1 set name=‘XX’ where id=10。

  • id 为唯一索引。

加锁行为:

  • 先在唯一索引 id 上加 id=10 的 X 锁。

  • 再在 id=10 的主键索引记录上加 X 锁,若 id=10 记录不存在,那么加间隙锁。

第三种情况:非唯一键 + RR,如下图所示。

 

 

假设条件是:

  • update t1 set name=‘XX’ where id=10。

  • id 为非唯一索引。

加锁行为:

  • 先通过 id=10 在 key(id) 上定位到第一个满足的记录,对该记录加 X 锁,而且要在 (6,c)~(10,b) 之间加上 Gap lock,为了防止幻读。然后在主键索引 name 上加对应记录的X 锁;

  • 再通过 id=10 在 key(id) 上定位到第二个满足的记录,对该记录加 X 锁,而且要在(10,b)~(10,d)之间加上 Gap lock,为了防止幻读。然后在主键索引 name 上加对应记录的X 锁;

  • 最后直到 id=11 发现没有满足的记录了,此时不需要加 X 锁,但要再加一个 Gap lock: (10,d)~(11,f)。

第四种情况:无索引 + RR,如下图所示。

 

 

假设条件是:

  • update t1 set name=‘XX’ where id=10。

  • id 列无索引。

加锁行为:

  • 表里所有行和间隙均加 X 锁。

至此,我们分析了四种索引在 RR 隔离级别下的加锁行为,那么在 RC 隔离级别下的加锁行为又是怎样的呢?这个问题留给你自己去思考,答案将在下一节课中给出。

 

在前文中,我们有提到分析锁问题的三个视图,在实际的使用中,可以在数据库发生阻塞的时候,将这三个视图做联合查询来帮助获取详细的锁信息,帮助快速定位找出造成死锁的元凶和被害者,以及具体的事务。

InnoDB 死锁

在 MySQL 中死锁不会发生在 MyISAM 存储引擎中,但会发生在 InnoDB 存储引擎中,因为 InnoDB 是逐行加锁的,极容易产生死锁。那么死锁产生的四个条件是什么呢?

  • 互斥条件:一个资源每次只能被一个进程使用; 

  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放; 

  • 不剥夺条件:进程已获得的资源,在没使用完之前,不能强行剥夺; 

  • 循环等待条件:多个进程之间形成的一种互相循环等待资源的关系。

在发生死锁时,InnoDB 存储引擎会自动检测,并且会自动回滚代价较小的事务来解决死锁问题。但很多时候一旦发生死锁,InnoDB 存储引擎的处理的效率是很低下的或者有时候根本解决不了问题,需要人为手动去解决。

 

既然死锁问题会导致严重的后果,那么在开发或者使用数据库的过程中,如何避免死锁的产生呢?这里给出一些建议:

  • 加锁顺序一致;

  • 尽量基于 primary 或 unique key 更新数据。

  • 单次操作数据量不宜过多,涉及表尽量少。

  • 减少表上索引,减少锁定资源。

  • 相关工具:pt-deadlock-logger。

资源争用

下面分享一个基于资源争用导致死锁的情况,如下图所示。

 

 

session1 首先拿到 id=1 的锁,session2 同期拿到了 id=5 的锁后,两者分别想拿到对方持有的锁,于是产生死锁。

元数据锁

下面分享一个 Metadata lock(即元数据锁)导致的死锁的情况,如下图所示。

 

 

session1 和 session2 都在抢占 id=1 和 id=6 的元数据的资源,产生死锁。

 

查看 MySQL 数据库中死锁的相关信息,可以执行 show engine innodb status\G 来进行查看,重点关注 “LATEST DETECTED DEADLOCK” 部分。

 

给大家一些开发建议来避免线上业务因死锁造成的不必要的影响。

  • 更新 SQL 的 where 条件时尽量用索引;

  • 加锁索引准确,缩小锁定范围;

  • 减少范围更新,尤其非主键/非唯一索引上的范围更新。

  • 控制事务大小,减少锁定数据量和锁定时间长度 (innodb_row_lock_time_avg)。

  • 加锁顺序一致,尽可能一次性锁定所有所需的数据行。

本课时到这里就全部结束了,今天主要讲了 MySQL 的事务及其特性、并发事务带来的问题、事务的隔离级别、多版本并发控制 MVCC、InnoDB 锁分类、InnoDB 锁算法、InnoDB 死锁及其优化建议。

Guess you like

Origin www.cnblogs.com/tesla-turing/p/12036568.html