- MySQL为处理并发问题提出数据库锁设计
- 根据加锁的范围,MySQL里面的锁能够大体分为全局锁、表级锁和行锁三类。
- 全局锁
- 就是对整个数据库实例加锁。MySQL提供了一个加全局锁的方法,命令是:
- Flush tables with read lock (FTWRL)
- 这个语句让数据库处于只读状态,其余的线程的如下语句会被阻塞:数据更新语句(数据的增删查改)、数据定义语句(包括建表、修改表结构等)和更新事务的提交语句。
- 全局锁的典型使用场景是,作全库逻辑备份。也就是把数据库的每一个表都select出来存成文本。
-
让整个数据库只读的弊端一、若是在主库上备份,在备份期间不能执行更新,业务基本上就得停摆;二、若是在从库上备份,那么备份期间从库不能执行主库同步过来的binlog,致使主从延迟。
-
如何备份数据库还能不影响数据库的正常功能?在可重复读隔离级别下开启一个事务。官方自带的逻辑备份工具是mysqldump,使用参数是single-transaction的时候,导数据以前就会启动一个事务,来确保拿到一致性视图。因为MVCC的支持,这个过程当中数据是能够正常更新的。single-transaction方法只适用于全部的表使用事务引擎的库。
-
- 何时须要FTWRL呢?
- 一致性读是好,可是前提是引擎要支持这个隔离级别。对于MyISAM这种不支持事务引擎的,就须要使用FTWRL
- 为何使用FTWRL而不是其它全库只读功能?好比set global readonly = true的方式?
- 一、有些系统中,readonly的值会被用来作其余逻辑,好比用来判断一个库是主库仍是备库。修改global变量的方式影响面更大。
- 二、在异常处理机制上有差别。执行FTWRL这个命令的客户端异常断开,那么MySQL会自动释放这个全局锁。而整个库设置为readonly以后,若是客户端发生异常,则数据库就会一直保持readonly状态。
表级锁,MySQL的表级锁也分为两种:一种是表锁,一种是元数据锁(meta data lock,MDL)mysql
- 表锁:
- 表锁的语法是:lock tables ... read/write。
- lock tables 语法即能限制其余线程的读写操做,也能限制本线程接下来的读写操做。
- 没有更细粒度的锁的时候,表锁能够用来处理并发的方式。InnoDB支持行锁,因此就不须要使用表锁了。
元数据锁MDL(metadata lock)
- MDL不须要显示使用,在访问一个表的时候会被自动加上。
- 在MySQL 5.5版本中引入了MDL,当对一个表作增删查改操做的时候,加MDL读锁;当对表结构变动操做的时候,加MDL写锁。
- 读锁之间不互斥
- 读写锁之间、写锁之间是互斥的。
给一个小表加个字段,致使整个库挂了?


如图所示,sessionA和sessionB不会互斥,可是sessionC在读锁没有释放的时候请求MDL写锁,就会阻塞,那后面须要写锁的也被阻塞了,若是这个表的查询操做还很是频繁,并且客户端有重试机制,这个库的线程很快就会爆满,这个库就崩掉了。
- 如何安全的给小表加个字段?
- 一、解决长事务、事务不提交,就会一直占着MDL锁。MySQL的information_schema库的innodb_trx表中,能够查找到当前执行中的事务。
- 比较理想的机制是,在alter table语句里面设定等待时间,若是在等待时间内拿到MDL写锁最好,拿不到就放弃。之后重试。
- MariaDB已经合并AliSQL的这个功能,因此这两个开源分支项目都支持DLL NOWAIT/WAIT n这个语法。
- ALTER TABLE tbl_name NOWAIT add column ...
ALTER TABLE tbl_name WAIT N add column ...
-
四个数据库设计语言:DDL(数据定义语言)、DML(数据操做语言)、DCL(数据控制语言)、TCL(事务控制语言)
-
MVCC
MVCC(Multi-Version Concurrency Control)即多版本并发控制。
MySQL的大多数事务型(如InnoDB,Falcon等)存储引擎实现的都不是简单的行级锁。基于提高并发性能的考虑,他们通常都同时实现了MVCC。当前不只仅是MySQL,其它数据库系统(如Oracle,PostgreSQL)也都实现了MVCC。值得注意的是MVCC并无一个统一的实现标准,因此不一样的数据库,不一样的存储引擎的实现都不尽相同。
-
小结
-
若是你发现你的应用程序里有lock tables这样的语句,须要追查一下,比较可能的状况是:一、要么是系统再用MyISAM这类不支持事务的引擎,要安排升级换引擎;二、引擎升级了,代码尚未升级。把lock tables 和 unlock tables 改为begin 和commit,问题就解决了。
-
思考备份通常都会在备库上进行,在用single-transaction方法作逻辑备份的过程当中,若是主库上的一个小表作了一个DDL,好比给表加了一列,这时候,从备库上会看到什么现象?