2022/1/30 6:04:57

本文主要是介绍锁,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

十五、锁

在数据库中,除传统的计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的资源,当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制。

1 锁分类

1.1 按操作类型分

  • 读锁(共享锁):当用户要进行数据的读取时,多个读操作可以同时进行而不会互相影响。共享锁可以同时加上多个。
  • 写锁(排它锁):当用户要进行数据的写入时,对数据加上排他锁。排他锁只可以加一个,他和其他的排他锁,共享锁都相斥。

1.2 按操作粒度分

  • 表锁:表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MYISAM与INNODB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。特点:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。
  • 页锁页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。特点:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
  • 行锁,行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁和排他锁。特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
开销 加锁速度 可能出现死锁 并发程度
表锁
页锁 中等 中等 中等
行锁

存储引擎使用什么类型的锁:

  • MyISAM采用表级锁
  • InnoDB支持行级锁和表级锁,默认为行级锁
  • BDB引擎采用页级锁

2 锁的使用

查看当前数据库中表的上锁情况:

show open tables;  
# 0 表示未上锁

2.1 表锁

表锁一般是MyISAM引擎使用。

添加表锁

lock table 表名1 read(write), 表名2 read(write), ...;

释放所有表锁

unlock tables;

会话session1将表A加读锁之后:

  • session1可以对A进行读操作,其它sessions也可以对A进行读操作
  • session1不能修改表A,其它sessions此时修改表A,会被提示阻塞直到锁被释放
  • session1此时不可以读其它表(比如表B)

会话session1将表A加写锁之后:

  • session1可以对A进行读操作,其它sessions不可以对A进行读操作
  • session1可以修改表A,其它sessions此时修改表A,会被提示阻塞直到锁被释放
  • session1此时不可以读其它表(比如表B)

结论:

  • MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行增删改操作前,会自动给涉及的表加写锁。

  • 简而言之,就是读锁会阻塞写,但是不会堵塞读。而写锁则会把读和写都堵塞。

其他分析工具:

可以通过检查table_locks_waitedtable_locks_immediate状态变量来分析系统上的表锁定:

show status like 'table%';
+----------------------------+--------+
| Variable_name              | Value  |
+----------------------------+--------+
| Table_locks_immediate      | 500440 |
| Table_locks_waited         | 1      |
| Table_open_cache_hits      | 500070 |
| Table_open_cache_misses    | 5      |
| Table_open_cache_overflows | 0      |
+----------------------------+--------+
5 rows in set (0.00 sec)
  • Table_locks_immediate:产生表级锁定的次数,表示可以立即获取锁的查询次数,每立即获取锁值加1;

  • Table_locks_waited:出现表级锁定争用而发生等待的次数(不能立即获取锁的次数,每等待一次锁值加1),此值高则说明存在着较严重的表级锁争用情况;

  • 此外,MyISAM的读写锁调度是写优先,这也是MyISAM不适合做写为主表的引擎。因为写锁后,其他线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永远阻塞。

2.2 行锁

行锁一般是InnoDB引擎使用。

InnoDB基于索引来自动加行锁:对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;对于普通SELECT语句,InnoDB不会加任何锁。

但是,行锁可能因为未使用索引而升级为表锁,所以除了检查索引是否创建的同时,也需要通过explain查询索引是否被实际使用。行锁相对于表锁来说,优势在于高并发场景下表现更突出,毕竟锁的粒度小。

3 乐观锁和悲观锁

数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。实现方式:使用数据库中的锁机制

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过version的方式来进行锁定。实现方式:乐一般会使用版本号机制或CAS算法实现。

两种锁的使用场景

从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。

但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。



这篇关于锁的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程