【Mysqlmysql的锁

2023年 9月 27日 37.0k 0

Mysql里的锁

全局锁

全局读锁: 阻止用户更新数据,但是允许用户读取数据。
全局写锁: 阻止用户读取和更新数据。
开启语句: FILUSH TABLES WITH READ LOCK, UNLOCK TABLES
一般只有迁移数据库才会使用全局锁,用的不多

表锁:

表共享读锁: 当一个事务获得了读锁,其它事务是不能获得该表的写锁,但是能再次获取读锁
表共享写锁: 当一个事务获得了写锁,其他事务是不能获得该表的读锁和写锁的

表锁使用场景:

  • 读操作远远大于写操作: 即这个表完全是用于进行被查询的,因此读取数据直接获取表锁即可,效率高
  • 数据量比较小: 这个时候即使修改影响其它操作效率,影响也不大
  • 对全表进行更新,删除,或者更改表结构
  • mysql使用表锁:

  • ALter table, Drop Table这些对全表进行操作的时候会锁住整个表,防止其它事务来读或写
  • lock tables [tablename] write, loca tables [tablename] read
  • SHOW OPEN TABLES WHERE In_use >0; 查看表锁。

    #查询进程
    show processlist;

    #杀死进程(等待锁的)
    kill 进程ID;

    行锁:

    行锁是Mysql中常用的锁定机制,对数据库表中的某一行数据进行锁定,是使用最多的。

    行锁优缺点

    优点: 锁粒度更小,对事务并发更友好,效率更高

    缺点: 对一行进行锁定,相较于表锁,需要更大的内存和cpu资源来保存锁信息

    行锁的种类

  • 共享锁(S): 也叫读锁,当一个事务读取一行锁时,其它事务也可以读取这一行数据,但是不能修改
  • 排它锁(X): 也叫写锁,当一行数据被上了写锁,其它事务对该数据不能读不能写。
  • 行锁只会在事务执行期间(commit,rollback执行之前)才会生效,事务执行时会添加行锁,执行完立马释放。

    行锁使用场景

  • 高并发读写: 行级锁允许多个事务并发的对不同行进行操作
  • 某一行进行操作,基于主键去操作单行内容
  • 复杂事务,复杂事务执行期间只锁定某个行,其它事务可以为其它行进行锁定,锁定的粒度小
  • 行锁上锁时机

  • select ... for update: 添加一个排它锁(X)
  • select ... lock in share mode: 加一个读锁(s)
  • select: 加一个读锁(s)
  • insert, update, delete: 加一个写锁(X)
  • 行锁的问题

  • 死锁: 事务A获取行A锁,请求行B锁;事务B获取行B锁,请求行A锁。死锁,超过时间回滚。
  • 资源消耗: 消耗太多资源来维护每一行的数据
  • 难以调试,性能出现问题,难以排查
  • 如果查询没有使用到索引, 会为每一行都添加行锁,升级为表锁了
  • 我们来举个行级锁在数据库中的使用:

  • 事务A设置排它锁: image.png
  • 另开事务B去修改他们:
  • image.png

    发现卡死了。

  • 这个时候去查看锁:
  • image.png

    可以看到事务B在等待写锁,lock_status处于wating状态, 只有事务A提交释放锁才能成功修改。

    意向锁

    当对行进行共享读,Mysql会为全表添加一个意向共享锁(IS)

    当对行进行修改时,Mysql会为全表添加一个意向排它锁(IX)

    • 在一个事务对一张表的某行添加S锁之前,它必须对该表获取一个IS锁或者优先级更高的锁,然后再添加S锁
    • 在一个事务对一张表的某行添加X锁之前,它必须对该表获取一个IX锁。

    为什么使用意向锁

    当事务A操作表中的某个数据时,事务B来查询全表,需要对表的每一行进行判断,看是否有写锁,这样的话,效率比较低。这个时候如果有一个意向排它锁,事务B看到这个排它锁就不会再去一行行判断是否有写锁,而是直接等待锁。

    意向锁可以让事务对全表进行操作的时候可以快速判断是否可以获取锁,而不用扫描每一行。

    意向锁冲突情况

    什么时候获取锁会发生锁冲突?

    下面是官网的图:

    下图里面的X与S是指对全表的操作。
    image.png

  • 意向锁之间是不会发生冲突的,因为意向锁是表明某个事务对某一行或者某几行进行了获取锁,而其它的行是可以再加锁的
  • 对与X:任何其它锁都会冲突,所以只能wait锁释放
  • 对于IX: X,S与其冲突,因为IX表示有修改,这个时候全表读,写是会被阻塞的
  • 对于S: X,IX与其冲突,因为全局读的时候,肯定不能写的
  • 对于IS: 与X冲突,因为IS表示有读取操作,这时候是不能全局修改的,会被阻塞
  • IX,IS是表级锁,不会和行级的X,S锁发生冲突。只会和表级的X,S发生冲突。

    记录锁

    记录锁就是为某行记录加锁,它封锁该行的索引记录:

    比如使用update ... where id = 1;

    注意: 这里的id必须为主键或唯一索引

    • id 列必须为唯一索引列或主键列,否则上述语句加的锁就会变成临键锁。
    • 同时查询语句必须为精准匹配(=),不能为 >、

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论