mysql 锁机制

锁的分类:

读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响。

写锁(排它锁):当前写操作没有完成前,它会阻断其他写锁和读锁。
为了尽可能提高数据库的并发度,每次锁定的数据范围越小越好,理论上每次只锁定当前操作的数据的方案会得到最大的并发度,但是管理锁是很耗资源的事情(涉及获取,检查,释放锁等动作),因此数据库系统需要在高并发响应和系统性能两方面进行平衡,这样就产生了“锁粒度(Lock granularity)”的概念。
 
一种提高共享资源并发发性的方式是让锁定对象更有选择性。尽量只锁定需要修改的部分数据,而不是所有的资源。更理想的方式是,只对会修改的数据片进行精确的锁定。任何时候,在给定的资源上,锁定的数据量越少,则系统的并发程度越高,只要相互之间不发生冲突即可。

表锁(偏读):偏向MyISAM存储引擎,开销小,加锁快;无死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行增删改操作前,会自动给涉及的表加写锁。 
MySQL的表级锁有两种模式:
 表共享读锁(Table Read Lock)
 表独占写锁(Table Write Lock)
结论:
 结合上表,所以对MyISAM表进行操作,会有以下情况: 
  1、对MyISAM表的读操作(加读锁),加锁的线程不能读其他表,不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其它进程的写操作。 
  2、对MyISAM表的写操作(加写锁),会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。
 简而言之,就是读锁会阻塞写,但是不会堵塞读。而写锁则会把读和写都堵塞

 

行锁(偏写):无索引行锁升级为表锁(比如说varchar类型没有加关键字引起索引失效);未提交前仅仅自己可见,其他线程访问不到更新的数据,读己之所写。

select加锁:

数据库的增删改操作默认都会加排他锁,而查询不会加任何锁

读锁:共享锁(Share Lock)
 
共享锁又称读锁,是读取操作创建的锁。其他用户可以并发读取数据,但任何事务都不能对数据进行修改(获取数据上的排他锁),直到已释放所有共享锁。
如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁。获准共享锁的事务只能读数据,不能修改数据。 
用法
SELECT ... LOCK IN SHARE MODE;
在查询语句后面增加 LOCK IN SHARE MODE ,Mysql会对查询结果中的每行都加共享锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请共享锁,否则会被阻塞。其他线程也可以读取使用了共享锁的表(行?),而且这些线程读取的是同一个版本的数据。

T1:begin tran

     select * from table lock in share mode

     update table set column1='hello'

T2:begin tran

     select * from table lock in share mode

     update table set column1='world'

假设 T1 和 T2 同时达到 select,T1 对 table 加共享锁,T2 也对 table 加共享锁,当 T1 的 select 执行完,准备执行 update 时,根据锁机制,T1 的共享锁需要升级到排他锁才能执行接下来的 update。在升级排他锁前,必须等 table 上的其它共享锁(T2)释放,同理,T2 也在等 T1 的共享锁释放。于是死锁产生了。

T1:begin tran

     update table set column1='hello' where id=10

T2:begin tran

     update table set column1='world' where id=20

 

这种语句虽然最为常见,很多人觉得它有机会产生死锁,但实际上要看情况

|--如果id是主键(默认有主键索引),那么T1会一下子找到该条记录(id=10的记录),然后对该条记录加排他锁,T2,同样,一下子通过索引定位到记录,然后对id=20的记录加排他锁,这样T1和T2各更新各的,互不影响。T2也不需要等。

|--如果id是普通的一列,没有索引。那么当T1对id=10这一行加排他锁后,T2为了找到id=20,需要对全表扫描。但因为T1已经为一条记录加了排他锁,导致T2的全表扫描进行不下去(其实是因为T1加了排他锁,数据库默认会为该表加意向锁,T2要扫描全表,就得等该意向锁释放,也就是T1执行完成),就导致T2等待。
mysql InnoDB引擎默认的修改数据语句,update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型,如果加排他锁可以使用select ...for update语句,加共享锁可以使用select ... lock in share mode语句。

写锁:

排他锁(eXclusive Lock)
共享锁又称写锁,如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。
用法
SELECT ... FOR UPDATE;(因为update本身更新带锁的,这个相当于给查询出来的语句加个排它锁)
       在查询语句后面增加 FOR UPDATE ,Mysql会对查询结果中的每行都加排他锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请排他锁,否则会被阻塞。

https://blog.csdn.net/c466254931/article/details/53463596--排它锁与共享锁

读锁:当读出数据后,其他事务不能修改,自己也不一定能修改,因为其他事务可以用共享锁进行锁住。
写锁:将查找的数据加上一个写锁,不允许其他事务获取这些记录的S锁与X锁。读出数据其他事务不能写,也不能加上读锁,只有自己可以读与修改。
写操作:
delete 删除一条数据时,先对记录加X锁,再执行删除操作
inset 插入一条记录时,会加隐式锁,来保护这条新插入的记录在本次事务提交前不被别的事务访问到
隐式锁:一个事务插入一条记录后,还未提交,这条记录会保存本次事务的ID,而其他的事务要式对这个记录加锁时会发现事务ID不对应,这时产生X锁,所以相当于插入一条记录时。隐式给这条记录加个X锁
update:如果被跟新的列,修改前没有导致存储空间的变化,那会先加X锁,再直接对记录进行修改。
如果被更新的列,修改前后导致存储空间发生了变化,那会给记录加X锁,然后将记录删掉,再insert一条新记录。
普通select语句没有锁

间隙索引:
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,
InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(GAP Lock)。
 
危害
因为Query执行过程中通过过范围查找的话,他会锁定整个范围内所有的索引键值,即使这个键值并不存在。
间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的危害

总结:
  Innodb存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会要更高一些,但是在整体并发处理能力方面要远远优于MyISAM的表级锁定的。当系统并发量较高的时候,Innodb的整体性能和MyISAM相比就会有比较明显的优势了。
  但是,Innodb的行级锁定同样也有其脆弱的一面,当我们使用不当的时候,可能会让Innodb的整体性能表现不仅不能比MyISAM高,甚至可能会更差。

优化建议:尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁。

尽可能较少检索条件,避免间隙锁

尽量控制事务大小,减少锁定资源量和时间长度

锁住某行后,尽量不要去调别的行或表,赶紧处理被锁住的行然后释放掉锁。

涉及相同表的事务,对于调用表的顺序尽量保持一致。

https://blog.csdn.net/soonfly/article/details/70238902

没利用到索引的话,inodb引擎默认的是表锁

在读已提交隔离下,获取某些行的锁后比如(xxx where b=1),另一个事务再插入insert(x.x,x,1)的话可以,在可重复读情况下不可以这样可以防止幻读。比如说

id 

1

6

7

11

18

当对select * from table where ID =7时会使用间隙锁锁住6-11间的数据,不能向里面插入这些数据。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值