mysql共享锁排他锁

阅读: 评论:0

mysql共享锁排他锁

mysql共享锁排他锁

一、概述

数据库锁简单来说,是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则。mysql存在多种搜索引擎,每种搜索引擎所针对的应用场景特点不太一样。每种搜索引擎的锁定机制都是为各自所针对的应用场景而设计的。各种搜索引擎的锁机制也有比较大的区别。

二、表锁

表级锁定是mysql中最大粒度的锁定机制。其实现逻辑非长简单,带来的负面影响最小。表锁会锁定整个表,所以不会带来死锁的问题。由于表锁会锁定整个表,会造成线程等待概率变高,降低并发能力。

使用表锁的存储引擎主要是:MyISAM、MEMORY、CSV等一些非事务性搜索引擎。

三、行锁

不少引擎都支持行锁,但不是所有的引擎都支持行锁,如MyISAM就不支持。这里我们主要分析InnoDB。

在InnoDB中,锁只有在事务结束时才释放。所以要把最有可能影响并发的操作往后放。

1.两阶段锁协议

比如,在线转账业务,用户A要给用户B转账,业务需要涉及以下操作:

(1)从A的账户余额中扣除金额

(2)B账户增加转账金额

(3)记录转账日志

如何安排这三个语句在事务中的顺序?

如果有C用户要给B用户转账,那么这两个事务中冲突部分是语句2。因为他们要同时更新同一条数据,如果将语句2放到最后,那么账户余额这一行锁等待的时间最少。最大程度的减少了事务之间的锁等待,提高并发度。

2.死锁和死锁检测

在并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都陷入无限等待状态,称为死锁。

事务A事务B

begin;

update user set balance = 100 where id = 1;

begin
 update user set balance = 200 where id = 2;
update user set balance = 201 where id = 2; 
 update user set balance = 101 where id = 1;
commit;commit;

事务A等待事务B释放id=2的锁,事务B等待事务A释放id=1的锁,事务A、B相互等待对方释放资源,就是进入了死锁状态。当出现死锁后,有两种解决策略:

  • 直接进入等待,直到超时。这个时间可以通过innodb_lock_wait_timeout来设置。
  • 另一种策略是 发起死锁检测,发现死锁后主动回滚死锁链条中的某一个事务,让其他事务得以继续进行。innodb_deadlock_detects设为on,表示开启这个逻辑。

3.共享锁和排他锁

共享锁又称读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据共用同一把锁,都能访问到数据,但是不能修改。

排他锁又称写锁,简称X锁,顾名思义,排他锁就是不能与其他锁并存,如果一个事务获得了一行数据的排他锁,其他事务就不能获得该行的其他锁(包括共享锁和排他锁),但是已获得了这行数据排他锁的事务可以对这行数据进行读取和修改。

(1) 排他锁

我之前认为一个事务获得了一行数据的排他锁后,其他事务就不能对这行数据读取和修改。其实不是这样,排他锁是指一个事务在一行数据上加排他锁后,其他事务不能再加其他的锁。mysql InnoDB引擎修改语句update delete insert 都会给所涉及的数据自动加排他锁,select语句不加任何类型的锁,如果加排他锁可以使用select ... for update语句,共享锁可以使用select ... lock in share mode语句。所以加过排他锁的数据行,其他事务是不能修改的,也不能通过for update 和lock in share mode查询,可以使用单纯的select语句查询。

  • 同一事务内加排他锁后可以查询和修改
    begin;
    select * from user where id = 1 for UPDATE;
    update user set `name` = '小花5' where id = 1;
    COMMIT

    update语句能够修改成功

  • 不同事务,一个事务加排他锁后其他事务不能再给这行数据加任何类型的锁

我navicat 开启三个窗口

第一个窗口执行

begin;
select * from user where id = 1 for UPDATE;

能够查询到一条数据

第二个窗口执行

begin;
select * from user where id = 1 for UPDATE;

会一直等待,50s后自动抛异常等待超时

[Err] 1205 - Lock wait timeout exceeded; try restarting transaction

第三个窗口执行

begin;
select * from user where id = 1 ;

可以查询到一条数据。纯select语句没有加任何锁。

2)共享锁和排他锁是否冲突

同样开启三个窗口

第一个窗口执行update语句,自动给id=1的数据加排他锁

begin;
update user set name = '小花1' where id = 1;

第二个窗口select 给id= 1的数据加共享锁

begin;
select * from user where id = 1 lock in SHARE MODE;

查询会一直等待,第一个窗口commit后第二个窗口才能查到数据。共享锁和排他锁是冲突的。

下面贴一下百度到了四种锁的逻辑关系:

 共享锁(S)排他锁(X)意向共享锁(IS)意向排他锁(IX)
共享锁(S)兼容冲突兼容冲突
排他锁(X)冲突冲突冲突冲突
意向共享锁(IS)兼容冲突兼容兼容
意向排他锁(IX)冲突冲突兼容兼容

 

参考网址:

.html

 

 

 

 

本文发布于:2024-02-02 20:20:50,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170687644946212.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:mysql
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23