mysql的锁机制(读锁,写锁,表锁,⾏锁,悲观锁,乐观锁,间隙锁)
读锁和写锁
介绍
MyISAM表锁中的读锁和写锁
1. 读锁(共享锁S): 对同⼀个数据,多个读操作可以同时进⾏,互不⼲扰。加锁的会话只能对此表进⾏读操作,其他会话也只能进⾏读
操作。MyISAM的读默认是加读锁。
2. 写锁(互斥锁X): 如果当前写操作没有完毕,则⽆法进⾏其他的读操作、写操作。当前会话只能对此表进⾏读,写操作,其他会话⽆法
微服务架构的实现必须具备什么能力进⾏任何操作。MyISAM的DML默认加写锁
mxc抹茶appInnoDB⾏锁中的读锁和写锁
1. 读锁(共享锁S):允许⼀个事务去读⼀⾏,阻⽌其他事务获得相同数据集的排他锁。若事务T对数据
对象A加上S锁,则事务T可以读
A但不能修改A,其他事务只能再对A加S锁,⽽不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。InnoDB通过使⽤lock in share mode加读锁,但是注意只锁覆盖索引
2. 写锁(互斥锁X):允许获取排他锁的事务更新数据,阻⽌其他事务取得相同的数据集共享读锁和排他写锁。若事务T对数据对象A加
上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。InnoDB所有的DML操作默认加写锁。
select可以通过for update加写锁,并且会锁住所有索引,不仅仅是索引覆盖的索引。
注意:
对于共享锁⼤家可能很好理解,就是多个事务只能读数据不能改数据。对于排他锁⼤家的理解可能就有些差别,我当初就犯了⼀个错误,以为排他锁锁住⼀⾏数据后,其他事务就不能读取和修改该⾏数据,其实不是这样的。排他锁指的是⼀个事务在⼀⾏数据加上排他锁后,其他事务不能再在其上加其他的锁。mysql InnoDB引擎默认的修改数据语句:update,delete,insert都会⾃动给涉及到的数据加上
排他锁,select语句默认不会加任何锁类型,如果加排他锁可以使⽤select …for update语句,加共享锁可以使⽤select … lock in share mode语句。所以加过排他锁的数据⾏在其他事务种是不能修改数据的,也不能通过for
update和lock in share mode锁的⽅式查询数据,但可以直接通过select …from…查询数据,因为普通查询没有任何锁机
制。但是注意在MyISAM引擎中因为读也会⾃动加上读锁,所以使⽤排它锁的时候是不能去读的,这点要和InnoDB区别开
此外,InnoDB对于共享锁和互斥锁,还拥有
操作(以表锁为例⼦)
加锁:locak table 表1 read/write ,表2 read/write ,...
释放锁(所有):unlock tables ;
查看哪些表加了锁:show open tables ; 1代表被加了锁
加读锁
##会话0加读锁
lock table tablelock read;
#操作
select*from tablelock;--读(查),可以
delete from tablelock where id =1;--写(增删改),不可以
select*from emp ;--读,不可以(emp为⾮锁表)
delete from emp where eid =1;--写,不可以
#会话1(⾮加锁会话)
select*from tablelock;--读(查),可以
c语言fgets返回值delete from tablelock where id =1;--写,会“等待”会话0将锁释放
select*from emp ;--读(查),可以 (emp为⾮锁表)
delete from emp where eno =1;--写,可以
结论:
当前会话(会话0):
⼀个会话给A表加了锁,则当前会话只能对A表进⾏读操作;
其他会话(会话1):
1. 可以对其他表(A表以外的表)进⾏读、写操作
2. 对A表:读-可以; 写-需要等待释放锁。
加写锁
#会话0加写锁
lock table tablelock write;
#其他⼤体与读锁相似,这⾥直接讲结论
结论:
当前会话(会话0):
1. 可以对加了写锁的表 进⾏任何操作(增删改查);mysql怎么读英语
2. 但是不能 操作(增删改查)其他表
其他会话(会话1):
对会话0中加写锁的表 可以进⾏增删改查的前提是:等待会话0释放写锁⾏锁和表锁和页⾯锁
介绍
1. 表锁 :⼀次性对⼀张表整体加锁,是MySQL各存储引擎中最⼤颗粒度的锁定机制。如MyISAM存储引擎使⽤表锁,开销⼩、实现逻
辑⾮常简单,带来的系统负⾯影响最⼩,加锁和释放锁快;⽆死锁;但锁的范围⼤,容易发⽣锁冲突,并发度低。在MyISAM中,因为不⽀持事务,因此只能⽤lock和unlock控制.InnoDB中,表锁还可以通过事务控制
2. ⾏锁 :⼀次性对⼀条数据加锁,锁定对象的颗粒度很⼩,也是⽬前各⼤数据库管理软件所实现的锁定颗粒度最⼩的。如InnoDB存储
引擎使⽤⾏锁,开销⼤,加锁慢;容易出现死锁;锁的范围较⼩,不易发⽣锁冲突,并发度⾼(很⼩概 率 发⽣⾼并发问题:脏读、幻读、不可重复度、丢失更新等问题)针对事务(commit和rollbcak)。注意当索引失效或者压根就没有索引时,会怎么办呢?我看过好多⽂章,都是说会变为表锁,但实际并不是这样,其实还是⾏锁。
3. 页⾯锁:锁定粒度界于表锁和⾏锁之间;开销和加锁时间界于表锁和⾏锁之间;会出现死锁;并发度⼀般 。使⽤页级锁定的主要是
BerkeleyDB存储引擎。
从上述特点可见,很难笼统地说哪种锁更好,只能就具体应⽤的特点来说哪种锁更合适!仅从锁的⾓度 来说:表级锁更适合于以查询为主,只有少量按索引条件更新数据的应⽤,如Web应⽤;⽽⾏级锁则更适合于有⼤量按索引条件并发更新少量不同数据,同时⼜有并发查询的应⽤,如⼀些在线事务处理(OLTP)系统。
MyISAM的表锁
MyISAM在执⾏查询语句(SELECT)前,会⾃动给涉及的所有表加读锁,在执⾏更新操作(DML)前,会⾃动给涉及的表加写锁。
所以对MyISAM表进⾏操作,会有以下情况:
a、对MyISAM表的读操作(加读锁),不会阻塞其他进程(会话)对同⼀表的读请求,但会阻塞对同⼀表的写请求。只有当读锁
释放后,才会执⾏其它进程的写操作。
b、对MyISAM表的写操作(加写锁),会阻塞其他进程(会话)对同⼀表的读和写操作,只有当写锁释放后,才会执⾏其它进程
的读写操作。
1. 操作
加锁:locak table 表1 read/write ,表2 read/write ,...
释放锁(所有):unlock tables ;
查看哪些表加了锁:show open tables ; 1代表被加了锁
分析表锁定的严重程度: show status like ‘Table_locks%’ ;
Table_locks_immediate :即可能获取到的锁数,即⽴刻能加锁的表数
Table_locks_waited:需要等待的表锁数(如果该值越⼤,说明存在越⼤的 锁竞争)
⼀般建议:
Table_locks_immediate/Table_locks_waited > 5000, 建议采⽤InnoDB引擎,否则MyISAM引擎
2. 注意别名问题
#对temp表进⾏加读锁,temp有两个字段(id,tid)
lock table temp read;
#通过别名对temp表进⾏查询操作
select t.*from temp t where t.id=1;
parseint未定义报错:ERROR 1100 (HY000): Table ‘t’ was not locked with LOCK TABLES
#加锁的时候加上别名
lock table temp as t read;
#还是同样的查询操作
select t.*from temp t where t.id=1;
±-----±-----+
| id | tid |
±-----±-----+
| 1 | 2 |
±-----±-----+
1 row in set (0.05 sec)
#注意此刻继续执⾏这个查询语句,原来的名字没⽤了
select*from temp;
ERROR 1100 (HY000): Table ‘temp’ was not locked with LOCK TABLES
3.锁的调度问题
MyISAM存储引擎的读锁和写锁是互斥的,读写操作是串⾏的。那么,⼀个进程请求某个 MyISAM表的读锁,同时另⼀个进程也请求同⼀表的写锁,MySQL如何处理呢?答案是写进程先获得锁。不仅如此,即使读请求先到锁等待队列,写请求后 到,写锁也会插到读锁请求之前!这是因为MySQL认为写请求⼀般⽐读请求要重要。这也正是MyISAM表不太适合于有⼤量更新操作和查询操作应⽤的原因,因为,⼤量的更新操作会造成查询操作很难获得读锁,从⽽可能永远阻塞。这种情况有时可能会变得⾮常糟糕!幸好我们可以通过⼀些设置来调节MyISAM 的调度⾏为。
通过指定启动参数low-priority-updates(默认是off/0),使MyISAM引擎默认给予读请求以优先的权利。
通过执⾏命令SET LOW_PRIORITY_UPDATES=1/on,使该连接发出的更新请求优先级降低。
通过指定INSERT、UPDATE、DELETE语句的LOW_PRIORITY属性,降低该语句的优先级。
虽然上⾯3种⽅法都是要么更新优先,要么查询优先的⽅法,但还是可以⽤其来解决查询相对重要的应⽤(如⽤户登录系统)中,读锁等待严重的问题。
另外,MySQL也提供了⼀种折中的办法来调节读写冲突,即给系统参数max_write_lock_count设置⼀个合适的值,当⼀个表的读锁达到这个值后,MySQL就暂时将写请求的优先级降低,给读进程⼀定获得锁的机会。
上⾯已经讨论了写优先调度机制带来的问题和解决办法。这⾥还要强调⼀点:⼀些需要长时间运⾏的查询操作,也会使写进程“饿死”!因此,应⽤中应尽量避免出现长时间运⾏的查询操作,不要总想⽤⼀条SELECT语 句来解决问题,因为这种看似巧妙的SQL语句,往往⽐较复杂,执⾏时间较长,在可能的情况下可以通过使⽤中间表等措施对SQL语句做⼀定的“分解”,使每 ⼀步查询都能在较短时间完成,从⽽减少锁冲突。如果复杂查询不可避免,应尽量安排在数据库空闲时段执⾏,⽐如⼀些定期统计可以安排在夜间执⾏。
4.⾼并发问题
MyISAM表的读和写是串⾏的,但这是就总体⽽⾔的。 当对同⼀个表进⾏查询和插⼊操作时,为了降低锁竞争的频率,在⼀定条件
下,MyISAM表也⽀持查询和插⼊操作的并发进⾏。根据concurrent_insert的设置,MyISAM是可以并⾏处理查询和插⼊的: MyISAM 存储引擎有⼀个系统变量concurrent_insert,专门⽤以控制其并发插⼊的⾏为,其值分别可以为0、1或2。
当concurrent_insert设置为NEVER(0)时,不允许并发插⼊。
c语言程序设计基础视频当concurrent_insert设置为AUTO(1)时,如果MyISAM表中没有空洞(即表的中间没有被删除的⾏),MyISAM允许在⼀个进程读表的同时,另⼀个进程从表尾插⼊记录。这也是MySQL的默认设置。
当concurrent_insert设置为ALWAYS(2)时,⽆论MyISAM表中有没有空洞,都允许在表尾并发插⼊记录。
我们来查看⼀下默认的的concurrent_insert
±------------------±------+
| Variable_name | Value |
±------------------±------+
| concurrent_insert | AUTO |
±------------------±------+
综合来看,concurrent_insert=2是绝对推荐的,⾄于max_write_lock_count=1和low-priority-updates=1,则视情况⽽定,如果可以降低写操作的优先级,则使⽤low-priority-updates=1,否则使⽤ max_write_lock_count=1。
InnoDB的⾏锁
InnoDB与MyISAM的最⼤不同有两点:⼀是⽀持事务(TRANSACTION),并且事务是默认⾃动进⾏提交的(可修改autocommit变量);⼆是采⽤了⾏级锁。⾏级锁与表级锁本来就有许多不同之处,另外,事务的引⼊也带来了⼀些新问题。
这⾥注意⼀个问题,和锁没什么关系,可以跳过:
1. 查看⾏锁的争⽤情况
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 |
±------------------------------±------+
如果发现锁争⽤⽐较严重,如InnoDB_row_lock_waits和InnoDB_row_lock_time_avg的值⽐较⾼,还可以通过设置InnoDB Monitors来进⼀步观察发⽣锁冲突的表、数据⾏等,并分析锁争⽤的原因。
2. 事务(Transaction)及其ACID属性
事务是由⼀组SQL语句组成的逻辑处理单元,事务具有4属性,通常称为事务的ACID属性。
原⼦性(Actomicity):事务是⼀个原⼦操作单元,其对数据的修改,要么全都执⾏,要么全都不执⾏。
⼀致性(Consistent):在事务开始和完成时,数据都必须保持⼀致状态。这意味着所有相关的数据规则都必须应⽤于事务的修改,以操持完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。
eg:有3个⼈进⾏转账操作,为了保证⼀致性(即3个⼈ 的账号⾦额总数不变),那在我写代码的时候,如果写了代码:A=A-5000;此时数据时不⼀致的。那就必须要写上,B=B+5000,或者是C=C+5000,这样的代码才能保证了数据库的⼀致性状态。
隔离性(Isolation):数据库系统提供⼀定的隔离机制,保证事务在不受外部并发操作影响的“独⽴”环境执⾏。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。具体看下⾯的⼏个隔离级别和并发问题。
持久性(Durable):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。
3. 并发事务带来的问题
相对于串⾏处理来说,并发事务处理能⼤⼤增加数据库资源的利⽤率,提⾼数据库系统的事务吞吐量,
从⽽可以⽀持可以⽀持更多的⽤户。但并发事务处理也会带来⼀些问题,主要包括以下⼏种情况。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论