mysql的全局锁和表锁 flush tables write read lock ;set global readonly=true; lock tables ;unlock tables,

##################################

全局锁:flush tables write read lock; set global readonly=1;--single-transaction

 

(1)flush tables write read lock :

1)对于 MyISAM 这种不支持事务的引擎,这时,我们就需要使用FTWRL 命令了。而使用mysqldump就可能得不到一致性的备份了。如果有的表使用了不支持事务的引擎,那么备份就只能通过 FTWRL 方法。这往往是 DBA 要求业务开发人员使用 InnoDB 替代 MyISAM 的原因之一。

2)对全局都管用,对任何用户都管用

3)如果执行FTWRL 命令之后由于客户端发生异常断开,那么 MySQL 会自动释放这个全局锁,整个库回到可以正常更新的状态。

 

 

(2)set global read_only=1:

 

标识作用:

# 通常用来标识一个mysql实例是主库还是从库,全局变量read_only=0,表示该实例为主库,全局变量read_only=1,表示该实例为从库:

1)全局变量read_only=0,表示该实例为主库。数据库管理员DBA可能每隔一段时间就会对该实例写入一些业务无关的数据来判断主库是否可写,是否可用,这就是常见的探测主库实例是否活着的。

2)全局变量read_only=1,表示该实例为从库。每隔一段时间探活,往往只会对从库进行读操作,比如select 1;这样进行探活从库。

 

注意事项:

1)readonly 对super用户权限无效。一般来说,业务方只有增删改查的dml权限,但是有的业务却需要ddl权限,比如建表,删表等ddl操作,因此有的业务可能有super权限,这就会导致业务仍然可以进行写数据,让read_olny失效。

2)将整个库设置为 readonly 之后,如果客户端发生异常,则数据库就会一直保持 readonly 状态,这样会导致整个库长时间处于不可写状态,风险较高。因此,设置read_only=1后,及时观察,发现异常就赶紧设置成read_only=0

 

 

(3)–single-transaction:(mysqldump的选项参数):只对事务性的存储引擎管用,通常DBA会要求业务只使用innodb存储引擎

 

mysqldump命令带上--single-transaction 参数后,会执行如下语句:

mysql>> set session transaction isolation level repeatable read;

mysql>> start transaction /*!40100 with consistent snapshot */;

 

 

--single-transaction
  此选项会将隔离级别设置为:REPEATABLE READ。并且随后再执行一条START TRANSACTION语句,让整个数据在dump过程中保证数据的一致性,这个选项对InnoDB的数据表很有用,且不会锁表。但是这个不能保证MyISAM表和MEMORY表的数据一致性。
  为了确保使用
--single-transaction命令时,保证dump文件的有效性。需没有下列语句ALTER TABLE, CREATE TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE,因为一致性读不能隔离上述语句。所以如果在dump过程中,使用上述语句,可能会导致dump出来的文件数据不一致或者不可用。
  如何验证上述的过程呢,可以开启general log看看过程是否如上述所说。

 

 

 

表锁:

 

1、lock tables table1 read,table2 read,table3 read

 

igoodful@a8-apple-iphone-db00.wh(glc) > show tables;
+---------------+
| Tables_in_glc |
+---------------+
| mobile        |
| user          |
+---------------+
2 rows in set (0.00 sec)

Fri Dec 20 17:42:35 2019
igoodful@a8-apple-iphone-db00.wh(glc) > show open tables where in_use >=1;
+----------+-------+--------+-------------+
| Database | Table | In_use | Name_locked |
+----------+-------+--------+-------------+
| glc      | user  |      1 |           0 |
+----------+-------+--------+-------------+
1 row in set (0.00 sec)

Fri Dec 20 17:42:47 2019
igoodful@a8-apple-iphone-db00.wh(glc) > lock tables user read;                          ######### 添加读锁
Query OK, 0 rows affected (0.00 sec)

Fri Dec 20 17:43:03 2019
igoodful@a8-apple-iphone-db00.wh(glc) > show open tables where in_use >=1;              ########## 表明:添加表读锁后,表被用次数加一
+----------+-------+--------+-------------+
| Database | Table | In_use | Name_locked |
+----------+-------+--------+-------------+
| glc      | user  |      2 |           0 |
+----------+-------+--------+-------------+
1 row in set (0.00 sec)

Fri Dec 20 17:43:08 2019
igoodful@a8-apple-iphone-db00.wh(glc) > select * from user;                             ########## 表明:可以读取锁住的表的数据。
+------+------+
| id   | name |
+------+------+
|    1 | 1    |
|    2 | 1    |
+------+------+
2 rows in set (0.01 sec)

Fri Dec 20 17:43:37 2019
igoodful@a8-apple-iphone-db00.wh(glc) > select * from mobile;                            ##########  表明:只能读取锁住的表的数据,不能查看没有锁住的表的数据
ERROR 1100 (HY000): Table 'mobile' was not locked with LOCK TABLES
Fri Dec 20 17:44:11 2019
igoodful@a8-apple-iphone-db00.wh(glc) >

 

 ########################################

在另一个会话线程中执行如下语句:

igoodful@a8-apple-iphone-db00.wh(glc) > select * from user;      ################# 表明:一个会话给表添加了读锁,那么不影响其他会话线程读取该表数据
+------+------+
| id   | name |
+------+------+
|    1 | 1    |
|    2 | 1    |
+------+------+
2 rows in set (0.00 sec)

Fri Dec 20 17:54:11 2019
igoodful@a8-apple-iphone-db00.wh(glc) > insert into user values (3,'3');       ################# 表明:一个会话给表添加了读锁,其他会话线程只能对该表进行读取,而不能对该表执行执行dml和ddl语句。
^CCtrl-C -- sending "KILL QUERY 233531" to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution was interrupted
Fri Dec 20 17:55:59 2019
igoodful@a8-apple-iphone-db00.wh(glc) > select connection_id();
+-----------------+
| connection_id() |
+-----------------+
|          233531 |
+-----------------+
1 row in set (0.00 sec)

Fri Dec 20 17:57:07 2019
igoodful@a8-apple-iphone-db00.wh(glc) > show open tables where in_use>0;;
+----------+-------+--------+-------------+
| Database | Table | In_use | Name_locked |
+----------+-------+--------+-------------+
| glc      | user  |      2 |           0 |
+----------+-------+--------+-------------+
1 row in set (0.00 sec)

ERROR:
No query specified

Fri Dec 20 17:57:25 2019
igoodful@a8-apple-iphone-db00.wh(glc) > lock tables user read;       ################# 表明:多个会话线程可以对同一张表添加读锁。
Query OK, 0 rows affected (0.00 sec)

Fri Dec 20 17:57:57 2019
igoodful@a8-apple-iphone-db00.wh(glc) >

 

一、表的读锁

如果一个会话线程执行了:lock tables table1  read, table2  read;

则有:

1)、该会话线程只能查询锁定的这几个表(table1,table2)的数据,没有被锁定的表,不能查询其数据

2)、其他事务不能对这两张表进行ddl、dml操作和write表锁

3)、其他会话可以对这两个表添加read锁,即表的读锁是共享锁,可以多个会话线程同时添加,互不影响

4)、这两张表当前被查询使用次数分别增加1,当执行会话执行 unlock tables语句时,这两张表当前被查询使用使用次数分别减1

 

 

 

igoodful@a8-apple-iphone-db00.wh(glc) > show open tables;
+--------------------+-------------------+--------+-------------+
| Database           | Table             | In_use | Name_locked |
+--------------------+-------------------+--------+-------------+
| glc                | mobile            |      0 |           0 |
| mysql              | db                |      0 |           0 |
| test               | host              |      0 |           0 |
| performance_schema | session_variables |      0 |           0 |
| glc                | user              |      2 |           0 |
| test               | user              |      0 |           0 |
| mysql              | user              |      0 |           0 |
+--------------------+-------------------+--------+-------------+
7 rows in set (0.00 sec)

Fri Dec 20 18:16:10 2019
igoodful@a8-apple-iphone-db00.wh(glc) >


##################################################################
1、出现在里面的表,表示的是:这些表都是打开的,且不是临时表。
2、如果In_use字段为0,则表示该表当前是被打开的状态,但是当前没有被使用。
3、如果In_use字段为2,则表示该表当前是被打开的状态,且正在被使用次数为2。 ################################################################## igoodful@a8-apple-iphone-db00.wh(glc) > show open tables; +--------------------+-------------------+--------+-------------+ | Database | Table | In_use | Name_locked | +--------------------+-------------------+--------+-------------+ | glc | mobile | 0 | 0 | | mysql | db | 0 | 0 | | test | host | 0 | 0 | | performance_schema | session_variables | 0 | 0 | | glc | user | 2 | 0 | | test | user | 0 | 0 | | mysql | user | 0 | 0 | +--------------------+-------------------+--------+-------------+ 7 rows in set (0.00 sec) Fri Dec 20 18:16:10 2019 igoodful@a8-apple-iphone-db00.wh(glc) > flush tables; Query OK, 0 rows affected (47.94 sec) Fri Dec 20 18:22:19 2019 igoodful@a8-apple-iphone-db00.wh(glc) > show open tables; Empty set (0.00 sec) Fri Dec 20 18:23:00 2019 ########################################################################### 1、flush tables会将缓存的所有表全部清空,即要读取这些表的数据就必须从磁盘加载到缓存。
2、当缓冲数目已经超过了table_open_cache设置的值,mysql开始使用LRU算法释放表对象。
3、当缓冲区已满,而连接想要打开一个不在缓冲中的表时。 ##########################################################

 

 

二、表的写锁

 

 

如果一个会话线程执行了:lock tables table1  write, table2  write;

则有:

1)、该会话线程只能查询锁定的这几个表(table1,table2)的数据,没有被锁定的表,不能查询其数据

2)、其他事务不能对这两张表进行ddl、dml操作、read表锁、write表锁,select读取这两张表也不行,表的写锁是互斥锁。

3)、这两张表当前被查询使用次数分别增加1,当执行会话执行 unlock tables语句时,这两张表当前被查询使用使用次数分别减1

 

 

3、表的解锁

LOCK TABLES语句为当前会话显式的获取表锁。
UNLOCK TABLES语句为当前会话显式的释放所有表锁(读写)。
lock tables与unlock tables只能为自己获取锁和释放锁,不能为其他会话获取锁,也不能释放由其他会话保持的锁。
一个对象获取锁,需具备该对象上的SELECT权限和LOCK TABLES权限。
##################################################################### ####################################################################
1、但是当会话发出另外一个LOCK TABLES时,当前会话锁定的所有表会隐式被解锁;
2、当服务器的连接被关闭时,当前会话锁定的所有表会隐式被解锁;

 

 

表锁:DML元数据锁:

MDL不需要我们记命令,它是隐式使用的,访问表会自动加上。它的主要作用是防止DDL(改表结构)和DML (CRUD表数据)并发的冲突。
举个栗子,线程A遍历查询表数据,这期间线程B删了表的某一列,这时A拿到的数据就跟表结构对不上,MySQL不允许这种事发生,所以在5.5版本引入了MDL。
它的逻辑很简单,对表进行CRUD操作,加MDL读锁;对表结构下手时,加MDL写锁。因此:
(1)读读不互斥,多线程可对同—张表增删改查;
(2)读写互斥、写写互斥,保证对表结构下手时只能有一个线程操作,另一个进入阻塞;

 

 

MDL全称为metadata lock,即元数据锁。MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务(显式或隐式)的时候,不可以对元数据进行写入操作。

因此从MySQL5.5版本开始引入了MDL锁,来保护表的元数据信息,用于解决或者保证DDL操作与DML操作之间的一致性。
对于引入MDL,其主要解决了2个问题:

(1)一个是事务隔离问题,比如在可重复隔离级别下,会话A在2次查询期间,会话B对表结构做了修改,两次查询结果就会不一致,无法满足可重复读的要求;

(2)另外一个是数据复制的问题,比如会话A执行了多条更新语句期间,另外一个会话B做了表结构变更并且先提交,就会导致slave在重做时,先重做alter,再重做update时就会出现复制错误的现象。

(3)元数据锁是server层的锁,表级锁,每执行一条DML、DDL语句时都会申请MDL锁,DML操作需要MDL读锁,DDL操作需要MDL写锁(MDL加锁过程是系统自动控制,无法直接干预,读读共享,读写互斥,写写互斥)

(4)申请MDL锁的操作会形成一个队列,队列中写锁获取优先级高于读锁。一旦出现写锁等待,不但当前操作会被阻塞,同时还会阻塞后续该表的所有操作。事务一旦申请到MDL锁后,直到事务执行完才会将锁释放。

(这里有种特殊情况如果事务中包含DDL操作,mysql会在DDL操作语句执行前,隐式提交commit,以保证该DDL语句操作作为一个单独的事务存在,同时也保证元数据排他锁的释放)。

注: 支持事务的InnoDB引擎表和不支持事务的MyISAM引擎表,都会出现Metadata Lock Wait等待现象。一旦出现Metadata Lock Wait等待现象,后续所有对该表的访问都会阻塞在该等待上,导致连接堆积,业务受影响。

 

 

 

#########################

##

 

##############################

posted @ 2019-12-20 17:48  igoodful  阅读(611)  评论(0编辑  收藏  举报