【MySQL】三种锁

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m18633778874/article/details/91357697

前言

    锁是计算机协调多个进程或纯线程并发访问某一资源的机制。锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。

MySQL三种锁  

     相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。比如,MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking)。InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。

  • 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
  • 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
  • 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般

锁应用

仅从锁的角度来说:

表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用;而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统。

MyISAM表锁

   查询表级锁争用情况,可以通过检查table_locks_waited和table_locks_immediate状态变量来分析系统上的表锁定争夺,如果Table_locks_waited的值比较高,则说明存在着较严重的表级锁争用情况。

mysql> show status like 'table%';
+-----------------------+-------+

| Variable_name         | Value |

+-----------------------+-------+

| Table_locks_immediate | 2979  |

| Table_locks_waited    | 0     |

+-----------------------+-------+

2 rows in set (0.00 sec))

MySQL表级锁的锁模式

  MySQL的表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)。锁模式的兼容性如表所示。

image.png

     可见,对MyISAM表的读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写请求;

对 MyISAM表的写操作,则会阻塞其他用户对同一表的读和写操作;MyISAM表的读操作与写操作之间,以及写操作之间是串行的!根据如表20-2所示的例子可以知道,当一个线程获得对一个表的写锁后,只有持有锁的线程可以对表进行更新操作。其他线程的读、写操作都会等待,直到锁被释放为止。 

image.png

 如何加表锁

    MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此,用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁。在本书的示例中,显式加锁基本上都是为了方便而已,并非必须如此。

表锁注意事项

   每一产品的金额小计 subtotal,假设我们需要检查这两个表的金额合计是否相符,可能就需要执行如下两条SQL:

    Select sum(total) from orders;

    Select sum(subtotal) from order_detail;

    这时,如果不先给两个表加锁,就可能产生错误的结果,因为第一条语句执行过程中,order_detail表可能已经发生了改变。因此,正确的方法应该是:

Lock tables orders read local, order_detail read local;

Select sum(total) from orders;

Select sum(subtotal) from order_detail;

Unlock tables;

InnoDB锁

      InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION);二是采用了行级锁。行级锁与表级锁本来就有许多不同之处,另外,事务的引入也带来了一些新问题。

获取InnoDB行锁争用情况

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     |

+-------------------------------+-------+

5 rows in set (0.01 sec)

 InnoDB行锁

  • 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
  • 排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。

      另外,为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),

这两种意向锁都是表锁。

 意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。

 意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。

image.png

总结如下

 1.   对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);

 2.  对于普通SELECT语句,InnoDB不会加任何锁;

 3.  事务可以通过以下语句显示给记录集加共享锁或排他锁。

 共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。

 排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE。

                                                                                 感谢您的访问!

猜你喜欢

转载自blog.csdn.net/m18633778874/article/details/91357697