mysql 锁

MySQL学习之——锁(行锁、表锁、页锁、乐观锁、悲观锁等)
https://crossoverjie.top/
https://blog.csdn.net/ztx114/article/details/78410727
https://blog.csdn.net/java_best/article/details/54708690

表锁更适用于以查询为主,只有少量按索引条件更新数据的应用;
行锁更适用于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用。

MyISAM表锁

MyISAM存储引擎只支持表锁。

mysql> show status like 'table%'
    -> ;
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Table_locks_immediate      | 100   |
| Table_locks_waited         | 0     |
| Table_open_cache_hits      | 0     |
| Table_open_cache_misses    | 0     |
| Table_open_cache_overflows | 0     |
+----------------------------+-------+
5 rows in set (0.00 sec)

Table_locks_immediate 空闲表锁个数
Table_locks_waited 锁争用个数。如果该值较高,并且有性能问题,应该首先优化查询,然后拆分表或使用复制。

表级锁:表共享读锁和表独占写锁。
读读可并行。
写会阻塞其他用户对同一表的读和写操作。

何时加表锁

myisam 在select前,会自动给涉及的所有表加读锁,在执行更新操作,会自动给涉及的表加写锁。
给表显示加锁,一般是为了在一定程度模拟事务操作,实现对某一时间点多个表的一致性读取。

mysql不支持锁升级??,lock后,只能访问显示加锁的表,不能访问未加锁的表;同时,读锁只能执行查询操作,不能执行更新操作。在自动加锁的情况下也基本如此,myisam总是一次获得sql语句所需要的全部锁。这也正是myisam不会出现死锁的原因。??(一次性获得全部锁,破坏了死锁的请求和保持条件)
使用lock tables时,不仅需要一次锁定用到的所有表,而且,别名也需要锁定

并发插入

在一定条件下,myisam可以支持读写并发进行。

系统变量,concurrent_insert
0,不允许并发插入
1,如果表中间没有被删除的行,允许一个进程读表的同时,另一个进程从表尾插入记录。默认设置。
2,始终允许在表尾并发插入记录。

通过定期在系统空闲时段执行optimize table语句来整理空间碎片,收回因删除记录而产生的中间空洞。

myisam的锁调度

写进程先获得锁。锁等待队列中,写锁会查到读锁请求之前。这也正是myisam表不太适合于有大量更新和查询操作的原因,因为,大量的更新操作会造成查询操作很难获得读锁,从而可能永远阻塞。
可以通过一些设置来调节myisam的调度行为。
low-priority-updates,使myisam引擎默认给予读请求优先权利
set low_priority_update=1,使该连接发出的更新请求优先级降低
指定insert、update、delete语句的low_priority属性,降低该语句的优先级

要么更新优先,要么查询优先

给max_write_lock_count 设置一个合适的值,当一个表的读锁达到这个值后,mysql就暂时将写请求的优先级降低

在可能的情况下可以通过使用中间表等措施对sql语句做一定的分解,使每一步查询都能在短时间内完成,从而减少锁冲突。如果复杂查询不可避免,应尽量安排在数据库空闲时段执行,比如一些定期统计可以安排在夜间执行。

InnoDB锁问题

与muisam最大不同是,支持事务,采用行级锁。

获取行级锁争用情况

innodb_row_lock%

设置innodb_monitors
打开监视器
打开监视器后会自动将监视情况写入日志,所以为避免日志庞大要设置服务器关闭写日志文件

InnoDB的行锁模式及加锁方法

  • 共享锁,允许一个事务去读一行,阻止其他事务获得相同数据集的排它锁。
  • 排它锁,允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。
    另外,为了允许行锁表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁,这两种都是表锁。
  • 意向共享锁,事务给数据行加共享锁之前必须先取得该表的意向共享锁
  • 意向排他锁,事务在各一个数据行加排它锁前必须先取得该表的意向排它锁。

意向锁是innodb自动加的,不需用户干预。对于更新语句,会自动加排它锁;select普通语句不会加锁。
用select...in share mode获得共享锁,主要确保没有人对这个记录进行更新操作,如果当前事务对该数据进行更新操作,会造成死锁?,需要select...for update 获得排它锁再更新。
同一个事务可以同时获得排他和共享锁??

死锁:
session1 加共享锁
session2 加共享锁
session1 更新
session1等待session2释放共享锁
session更新
session2等待session1释放共享锁

加排它锁:其他事务可正常查询,如果加共享锁会进行等待。

InnoDB行锁实现方式

通过给索引上的索引项加锁来实现的,只有通过索引条件检索数据,InnoDB才使用行锁,否则使用表锁。

锁冲突:因为是针对索引加锁,所以访问不同行的记录,如果是使用相同的索引键会出现锁冲突

id有索引name没有那么,
session1
where id = 1 and name = '1' for update

session2
where id = 1 and name = '4' for update
会等待锁

当表有多个索引时,不同事务可以使用不同的索引锁定不同的行,换句话说,有一个索引锁定一行后,其他索引不可锁定。

即便条件使用了索引字段,但是是否使用索引来检索数据是有mysql通过判断不同执行计划代价来决定的,如果认为全表扫描效率更高,比如对一些很小的表,它不会使用索引,这种情况下是使用表锁。
因此,在分析锁冲突时,别忘了检查sql的执行计划,已确认是否真正使用了索引
explain检查执行计划
类型转换??检索值的数据类型和索引字段不同,虽然mysql会进行数据类型的转换,但却不会使用索引,从而导致innodb使用表锁
如,条件中不是和varchar类型比较,会对title进行类型转换,执行全表扫描

加索引
mysql> alter table techo add index title(title(100));

varchar类型
mysql> explain select * from techo where title=56446545;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | techo | ALL  | title         | NULL | NULL    | NULL |   37 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

非varchar类型
mysql> explain select * from techo where title=56446545;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | techo | ALL  | title         | NULL | NULL    | NULL |   37 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

间隙锁(Next-Key锁)

当用范围条件检索数据,并请求共享或排它锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;
对于键值?在条件范围内但并不存在的记录,叫做间隙(GAP),InnoDB也会对这个间隙加锁,这种锁机制就是所谓的间隙锁。
使用间隙锁是为了防止幻读,另外一方面,是为了满足其恢复和复制的需要。

要尽量使用相等条件来访问更新数据,避免使用范围条件。但是使用相等条件给不存在的记录加锁,也会使用间隙锁。

恢复和复制的需要,对innodb锁机制的影响

通过BINLOG记录执行成功的insert、update、delete更新操作的sql语句,并由此实现mysql数据库的恢复和主从复制。

复制就是在slave mysql 不断做基于BINLOG的恢复。

恢复机制有以下特点:

  • 恢复是sql语句级的,也就是重新执行BINLOG中的sql语句。而oracle是基于数据库文件块的。
  • binlog是按照事务提交的先后顺序记录的,恢复也是按照这个顺序进行的。

所以mysql的恢复机制,要求事务串行化。
innodb无论什么隔离级别都要用间隙锁。
如果没有间隙锁,那假设表x中id=1的记录不存在,在事务a执行select * from x where id<100 但未提交时,又有事务b执行insert into x(id) value(1) 后提交了。那在binlog中的记录就是先b后a,这样a就幻读了。

另外,对于insert into target select * from source where... 和 create table new ...select...from source where... CTAS?这种语句,用户并没有对source做任何更新操作,但仍然会加共享锁。
其实使用多版本数据一致性读技术也可以实现相同的结果。但是这里mysql并没有使用它。
这是因为不加锁的话,如果在上述语句执行过程中,其他事务对source做了更新操作,就可能导致数据恢复的结果错误。如果复制的会,会导致主从数据库数据不一致。
innodb_locks_unsafe_for_binlog默认为off。
因此,INSERT...SELECT...和 CREATE TABLE...SELECT...语句,可能会阻止对源表的并发更新,造成对源表锁的等待。如果查询比较复杂的话,会造成严重的性能问题,我们在应用中应尽量避免使用。实际上,MySQL将这种SQL叫作不确定(non-deterministic)的SQL,不推荐使用。
可以采用来两种措施代替insert select和create table select语句

  • 不推荐。将innodb_locks_unsafe_for_binlog设为on,强制使用MVCC。但可能无法用binlog正确地恢复或复制数据。
  • 使用 select * from source into outfile ' ' terminated by ',' 和 load data infile ' ' into table x fields terminated by ','

innodb在不同隔离级别下的一致性读和锁的差异

innodb什么时候使用表锁

  • 事务需要更新大部分或全部数据,表又大,可以考虑直接使用表锁来提高该事务的执行速度
  • 事务涉及多个表,可能引起死锁造成回滚

使用lock tables表锁需要注意:

  • 仅当autocommit=0、innodb_table_locks=1(默认设置)时,InnoDB层才能知道MySQL加的表锁,MySQL Server也才能感知InnoDB加的行锁,这种情况下,InnoDB才能自动识别涉及表级锁的死锁;
  • 在用 LOCK TABLES对InnoDB表加锁时要注意,要将AUTOCOMMIT设为0,否则MySQL不会给表加锁;事务结束前,不要用UNLOCK TABLES释放表锁,因为UNLOCK TABLES会隐含地提交事务;COMMIT或ROLLBACK并不能释放用LOCK TABLES加的表级锁,必须用UNLOCK TABLES释放表锁。

关于死锁

myisam是deadlock free 无死锁的,这是因为MyISAM总是一次获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。

innodb因为是逐步获得锁的,因此可能发生死锁。
发生死锁后,innodb一般都能自动检测到,并使一个事务释放锁并回滚,让另一个事务得以继续进行。
锁等待超时参数innodb_lock_wait_timout 可解决表锁或外部锁死锁情况。并且在并发访问比较高的情况下,如果大量事务因无法立即获得所需的锁而挂起,会占用大量计算机资源,造成严重性能问题,甚至拖垮数据库。通过设置超时,可以避免这种情况发生。

避免死锁的常用方法。

  • 在应用中,如果不同的程序会并发存取多个表,应尽量约定以相同的顺序来访问表,这样可以大大降低产生死锁的机会。在下面的例子中,由于两个session访问两个表的顺序不同,发生死锁的机会就非常高!但如果以相同的顺序来访问,死锁就可以避免。
  • 在程序以批量方式处理数据的时候,如果事先对数据排序,保证每个线程按固定的顺序来处理记录,也可以大大降低出现死锁的可能。
  • 如果要更新记录,应该直接申请足够级别的锁,即排它锁,而不应先申请共享锁,更新时再申请排它锁。因为期间可能其他事务获得了共享锁。

如果出现死锁,可以用show engine innodb status 命令来确定最后一个死锁产生的原因。
返回结果中有死锁相关事务的详细信息。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • 当一个系统访问量上来的时候,不只是数据库性能瓶颈问题了,数据库数据安全也会浮现,这时候合理使用数据库锁机制就显得异...
    初来的雨天阅读 3,560评论 0 22
  • 一、概述 数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种...
    忘忧谷主阅读 589评论 0 3
  • 概述 数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则...
    datazhen阅读 755评论 0 2
  • MySQL的事务支持 MySQL的事务支持不是绑定在MySQL服务器本身,而是与存储引擎相关: MyISAM:不支...
    但莫阅读 489评论 0 6
  • MyISAM 和 MEMORY 存储引擎采用的是表级锁;InnoDB 存储引擎即支持行级锁,也支持表级锁,但默认情...
    微日月阅读 892评论 0 0