根据加锁范围,mysql中的锁的大致可以分为全局锁,表锁,行锁。
全局锁
全局锁就是对整个数据库实例加锁。通过flush table with read lock命令,将堆数据库加读锁。数据库编程只读状态,常用来作为数据库备份的时候使用。但是,在事务引擎中,并不是通过加全局锁来备份的,我们都知道在innodb引擎的RR隔离级别下,在导数据之前会开启一个事务,由于MVCC的支持,数据库还是可以进行更新操作的。那为什还需要用全局锁来备份呢?原因是只有事务引擎才支持。
通过官方提供的逻辑备份工具mysqldump,使用参数-single-transaction。
表锁
- 表锁通过命令lock tables ... T read/write可以提供表的读/写锁。
- 元数据锁(meta data lock):MDL不需要显示的使用,在访问一个表的时候会自己加上。
如何安全的给小表加字段?
由于有MDL,加入我们给小表加字段,加入之前已经有访问表的操作了,此时加字段操作将会堵塞,直到之前的访问结束,同时由于加字段操作堵塞了,之后的操作也会堵塞。导致系统不可读写。
- 方法一:加入有一个访问表的长事务,那么不加字段,或者结束长事务。
- 方法二:给加字段一个等待时间,在等待时间能没有完成结束。
行锁
并不是所有的引擎都支持行锁,MyISAM不支持行锁,innodb则支持。mysql中的两阶段锁。当我们开启事务的时候,当我们对一行数据进行修改的时候,在另一事务中,我们还可不可以再修改这一行数据呢?答案是不可以,因为事务1会触发行锁,事务2的修改操作将会堵塞直到事务1提交,行锁才释放。所以在innodb引擎中行锁并不是使用完就释放的,得事务提交之后才释放。
死锁和死锁检测
当出现资源的循环依赖的时候,就容易造成死锁。
解决方法:
- 设置超时时间,通过设置innodb_lock_wait_timeout,默认50s。
- 开启死锁检测,通过设置参数innodb_deadlock_detect=on。
弊端:
设置超时时间并不是一个好办法,因为在实际中很难设置出合适的时间。死锁检测也并不是一个很好的办法,假如对于一个热点数据更新操作,每次都需要判断是否死锁,这将是一个很耗费cpu的事情,会造成我们的数据库cpu达到了100%但是每秒处理的事务却很少。
怎么解决热点数据更新导致的性能问题?
对于热点数据,最好的处理方法就是分流,或者消息队列。分流指的是将处理分到多行中处理,降低某一行的并发量,消息队列的处理方式就是将操作保存到小实习队列中排队处理。