MySQL中锁的类型
根据锁的范围,MySQL可以分为全局锁、表级锁、行锁等。
一、全局锁
使用场景:
全库的逻辑备份
,可以使用Flush tables with read lock (FTWRL)命令来加全局读锁,来对整个库的数据备份。
也就是在加锁期间,整个库对外都是只读的,但是在读写分离、一主多从架构下,会出现问题:
- 如果是主库备份,那么整个架构都不能处理外部的更新操作,整个系统就会停止对外业务的处理。
- 如果是从库备份,为了保证主从一致性,从库需要定期更新binlog日志,在只读的情况下就不能执行binlog,导致主从数据不一致。
MySQL自带的备份工具mysqldump。如果mysqldump使用了–single-transaction参数
,就会在备份之前启动一个事务,获得read view。由于支持了MVCC
,备份的过程是可以更新的,也就不会出现上面的问题了。
那么,FTWRL的意义何在呢?
对于MySQL的MyISAM存储引擎并不支持事务,因此也就没有MVCC机制了,我们只能通过FTWRL加锁来保证备份的一致性。
那为什么不能使用set global readonly=true的方式呢?来保证整个库对于外部是只读的呢?
- readonly 我们通常会用来标志一个库是主库还是从库,所以不建议使用
- 异常机制,当客户端出现异常了,MySQL会自动释放全局锁。如果使用global readonly,如果客户端出现问题了,整个库会保持readonly状态,导致整个系统出现问题。
表级锁
表级锁分为:表锁和元数据锁
表锁
一般是我们通过lock tables…read/write来对某个表加读锁或者写锁,保证当前线程执行的过程中避免其他线程的干扰,
元数据锁(MDL)
在访问一个表时会被自动加上来保证读写的正确性,也就是在你增删改查的过程中,避免其他线程对表结构修改。
通常在进行增删改查时,会给表加MDL读锁,在对表结构修改时,会加MDL写锁。
MDL读读不互斥,读写、写写是互斥的。
所以尽量避免使用长事务
,会阻塞MDL写锁,在进行表结构修改的时候避免锁住增删改查操作,导致系统奔溃。
行锁
对于MySQL中的行锁是个存储引擎自己实现的,所以并不是所有的存储引擎都支持行锁,比如:MyISAM,就只能使用表锁,这样会非常影响并发度。
在InnoDB事务中,行锁是在需要的时候加
,但并不是不需要时就释放,需要等到事务结束以后才会释放
。
行锁虽然能提高表的并发度,但是会引发死锁问题,所以一般我们在一个事务中会把有可能出现并发冲突的行锁放到事务的最后,减少持有锁的时间。
总结:
对于MySQL来说,通过加全局锁来对整个库进行备份(mysqldump工具),如果存储引擎支持事务,可以使用–single-transaction参数来保证在备份的过程中可以执行更新操作(MVCC,一致性视图)。如果不支持事务,可以使用FTWRL。
一般情况下我们能用行级锁就用行级锁,来提供整个表的并发度。行锁的释放是在事务结束
最后使用表级锁(MDL)一定要保证不要因为对表结构的更新阻塞了整个系统的增删改查操作,MDL的释放是在事务提交结束后。