《MySQL实战45讲》学习笔记——锁

全局锁

对整个数据库实例加锁。命令是:Flush tables with read lock。使用这个命令后,数据库编程只读。全局锁的典型使用场景是做全库的逻辑备份。

将整个库锁定有很大缺点:

  • 如果在主库上备份,备份期间所有更新不能执行,业务基本停摆
  • 如果在从库上备份,备份期间不能从主库同步数据,造成主从延迟

官方的逻辑备份工具是mysqldump,使用-single-transaction参数可以在备份前启动一个事务,拿到一致性视图。由于MVCC的支持,这个过程中数据可以正常更新。

但是single-transaction模式只适用于所有的表都使用了支持事务的引擎(比如InnoDB),否则可能会造成数据不一致。MyISAM就不支持事务。

set global readonly=true也可以将全库设置为只读,备份数据还是建议使用FTWRL方式,因为:

  • 有些系统中,readonly=true会被用来做其他逻辑判断,比如判断一个库是主库还是从库,这样修改readonly可能会造成意外影响。
  • FTWRL模式下如果客户端发生异常断开,整个库会自动恢复正常状态,而readonly不会。

表级锁

表级锁有两种:一种是表锁,一种是元数据锁(MDL)。

在没有出现更细粒度的锁的时候,表锁是最常用的处理并发的方式。而对于InnoDB这种支持行锁的引擎,一般不使用lock tables命令来控制并发。

MDL不需要显示使用,在访问一个表的时候会自动加上。当对一个表做增删改查操作的时候,加MDL读锁;在修改表结构的时候,加MDL写锁。

给表加字段的时候要注意:MySQL的读写锁是队列形式的,如果一个写锁在等待,后边的读锁也加不上,会造成该表的读写都不可用。

行锁是存储引擎自己实现的,并不是所有引擎都支持行锁。

两阶段锁

在InnoDB事务中,行锁是需要的时候才加上的,但是并不是不需要了就立即释放,而是等到事务结束才释放。这个就是二阶段锁协议。

最佳实践

如果事务中要锁多个行,要把最可能造成冲突的锁尽量往后放。文中举了一个买电影票的例子,要把更新影院的数据放在最后。

死锁和死锁检测

例子:

事务A要更改行1和2,事务B要更改行2和1。事务A更改完行1的时候恰好事务B更改了行2。这样,事务A持有行1的行锁,请求行2的行锁;事务B持有行2的行锁,请求行1的行锁,造成死锁。

死锁解决办法:

  • InnoDB有一个参数innodb_lock_wait_timeout(默认50秒),超时回滚
  • 将innodb_deadlock_detect设置为on,发现死锁即回滚某一个事务。

因为方案1中的参数大小不好设置,一般采取方案2。

方案1如果设置太大,处理死锁速度太慢,如果设置太小,会造成误伤。方案2随着并发数增大,开销会迅速增大,每个锁都会检测。

死锁检测要花费大量的CPU资源,如果解决更新热点造成的性能问题呢?

  • 关闭死锁检测,业务保证不出现死锁(不推荐,不一定可行)
  • 控制并发度,可以利用中间件排队
  • 修改业务逻辑,将热点行拆成多行。比如影院的问题,可以给影院建立虚拟账户。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值