MySQL权限篇之LOCK TABLES及元数据锁
2016-03-29 10:20
555 查看
LOCK TABLES,锁表(或者视图)权限。
可以锁住那些你拥有select权限的表,以防止其他session访问或者修改这个表。
如果锁住视图,那么视图的所有基表都被锁住。
如果锁住的表上有触发器,那么和这个触发器所有相关的表都被锁住。
很明显,临时表由于其固有特性,lock table 临时表实际是没有意义的,虽然不报错,但实际也被忽略的。
要锁住某张表的前提是要拥有表上select 权限。
lock table有如下两种表达方式:
lock table xxx read,只读方式锁住xxx,该表只能被select,不能被修改。如果在lock时,该表上存在事务,则lock语句挂起,直到事务结束。多个会话可以同时对表执行该操作。
lock table xxx write,读写方式锁住xxx,lock table的会话可以对表xxx做修改及查询等操作,而其他会话不能对该表做任何操作,包括select也要被阻塞。
可以同时锁住多个表。
授予ut01@%权限:
D:\temp>mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 38
Server version: 5.7.11-log MySQL Community Server (GPL)
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> drop user if exists 'ut01'@'%';
Query OK, 0 rows affected (0.09 sec)
mysql> drop user if exists 'ut02'@'%';
Query OK, 0 rows affected, 1 warning (0.05 sec)
mysql> show warnings;
+-------+------+---------------------------------+
| Level | Code | Message |
+-------+------+---------------------------------+
| Note | 3162 | User 'ut02'@'%' does not exist. |
+-------+------+---------------------------------+
1 row in set (0.00 sec)
mysql> create user 'ut01'@'%' identified by '20127163';
Query OK, 0 rows affected (0.08 sec)
mysql> show grants for 'ut01'@'%';
+----------------------------------+
| Grants for ut01@% |
+----------------------------------+
| GRANT USAGE ON *.* TO 'ut01'@'%' |
+----------------------------------+
1 row in set (0.00 sec)
mysql> grant lock tables on test.* to 'ut01'@'%';
Query OK, 0 rows affected (0.08 sec)
mysql> show grants for 'ut01'@'%';
+---------------------------------------------+
| Grants for ut01@% |
+---------------------------------------------+
| GRANT USAGE ON *.* TO 'ut01'@'%' |
| GRANT LOCK TABLES ON `test`.* TO 'ut01'@'%' |
+---------------------------------------------+
2 rows in set (0.00 sec)
mysql> grant select on test.* to 'ut01'@'%';
Query OK, 0 rows affected (0.05 sec)
mysql> select * from sys_menu;
+--------+--------------+-----------+
| menuId | menuParentId | menuUrlId |
+--------+--------------+-----------+
| 201 | 0 | 9001 |
| 202 | 201 | 9002 |
| 203 | 201 | 9003 |
| 204 | 202 | 9004 |
| 205 | 203 | 9005 |
| 206 | 204 | 9006 |
+--------+--------------+-----------+
6 rows in set (0.03 sec)
mysql> delete from sys_menu where menuid=201;
<hang....>
ERROR 1317 (70100): Query execution was interrupted
mysql>
mysql> select * from sys_menu;
+--------+--------------+-----------+
| menuId | menuParentId | menuUrlId |
+--------+--------------+-----------+
| 201 | 0 | 9001 |
| 202 | 201 | 9002 |
| 203 | 201 | 9003 |
| 204 | 202 | 9004 |
| 205 | 203 | 9005 |
| 206 | 204 | 9006 |
+--------+--------------+-----------+
6 rows in set (0.00 sec)
mysql>
该用户操作:
C:\Users\Administrator>mysql -u'ut01'
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 40
Server version: 5.7.11-log MySQL Community Server (GPL)
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> use test
Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| sys_menu |
| sys_role |
| sys_role_menu |
+----------------+
3 rows in set (0.00 sec)
mysql> lock table sys_menu read;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from sys_menu;
+--------+--------------+-----------+
| menuId | menuParentId | menuUrlId |
+--------+--------------+-----------+
| 201 | 0 | 9001 |
| 202 | 201 | 9002 |
| 203 | 201 | 9003 |
| 204 | 202 | 9004 |
| 205 | 203 | 9005 |
| 206 | 204 | 9006 |
+--------+--------------+-----------+
6 rows in set (0.00 sec)
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
mysql>
即使该用户有delete权限:
mysql> use test
Database changed
mysql> lock table sys_menu read;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from sys_menu where menuId=201;
ERROR 1099 (HY000): Table 'sys_menu' was locked with a READ lock and can't be updated
mysql>
使用lock table xxx read锁住表后,包括自己session在内的所有会话都不能修改表,只能select表。
另外,会话使用lock table方式锁住了某表之后,那么该会话只能操作(包括select)那些被锁住的表,其他表不能操作,直到unlock tables结束。
mysql> lock table sys_menu read;
Query OK, 0 rows affected (6.43 sec)
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| sys_menu |
| sys_role |
| sys_role_menu |
+----------------+
3 rows in set (0.00 sec)
mysql> select * from sys_role;
ERROR 1100 (HY000): Table 'sys_role' was not locked with LOCK TABLES
mysql> delete from sys_role where 1=1;
ERROR 1100 (HY000): Table 'sys_role' was not locked with LOCK TABLES
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
mysql> lock table sys_menu write;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from sys_role;
ERROR 1100 (HY000): Table 'sys_role' was not locked with LOCK TABLES
mysql> delete from sys_role where 1=1;
ERROR 1100 (HY000): Table 'sys_role' was not locked with LOCK TABLES
mysql>
在使用mysqldump导出数据时,默认会add-lcoks,比如:
C:\Users\Administrator>mysqldump --add-locks -B test > d:\temp\test.add-locks.sql
C:\Users\Administrator>
那么在bulk insert之前和之后有如下的lock语句:
LOCK TABLES `sys_menu` WRITE;
/*!40000 ALTER TABLE `sys_menu` DISABLE KEYS */;
#表示暂不维护索引,待插入完毕之后,再维护索引。但是由于InnoDB表的结构,所以该语句对于innodb表然并卵。
INSERT INTO `sys_menu` VALUES (201,0,9001),(202,201,9002),(203,201,9003),(204,202,9004),(205,203,9005),(206,204,9006),(207,201,9007),(208,202,9008);
/*!40000 ALTER TABLE `sys_menu` ENABLE KEYS */;
UNLOCK TABLES;
也可以通过如下方式禁用lock语句:
C:\Users\Administrator>mysqldump --skip-add-locks -B test > d:\temp\test.add-locks.sql
C:\Users\Administrator>
此时:
/*!40000 ALTER TABLE `sys_menu` DISABLE KEYS */;
INSERT INTO `sys_menu` VALUES (201,0,9001),(202,201,9002),(203,201,9003),(204,202,9004),(205,203,9005),(206,204,9006),(207,201,9007),(208,202,9008);
/*!40000 ALTER TABLE `sys_menu` ENABLE KEYS */;
lock tables的语句就没有了。
当然,如果有某个会话使用lock tables语句锁住了某个表,那么mysqldump在导出该表时也会hang住。
元数据锁
为了保证事务的可串行化。在一个事务中被操作(查询,修改等)的那些表,数据库必须保证其他会话不能修改这些表的表结构。
比如,一个会话执行了如下操作:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from sys_menu;
+--------+--------------+-----------+
| menuId | menuParentId | menuUrlId |
+--------+--------------+-----------+
| 201 | 0 | 9001 |
| 202 | 201 | 9002 |
| 203 | 201 | 9003 |
| 204 | 202 | 9004 |
| 205 | 203 | 9005 |
| 206 | 204 | 9006 |
| 207 | 201 | 9007 |
| 208 | 202 | 9008 |
+--------+--------------+-----------+
8 rows in set (5.92 sec)
mysql>
该会话显示开启了一个事务,并且select了一个表sys_menu。那么数据库会在这个表上保持“元数据锁”。以防止其他会话修改这个表的表结构。
比如,另一个会话执行:
mysql> use test
Database changed
mysql> ALTER TABLE `test`.`sys_menu`
-> DROP COLUMN `menuUrlId`;
<一直hang住,直到前面的会话结束事务>
这个会话不能执行的有ddl操作,以及lock table write操作。
可以锁住那些你拥有select权限的表,以防止其他session访问或者修改这个表。
如果锁住视图,那么视图的所有基表都被锁住。
如果锁住的表上有触发器,那么和这个触发器所有相关的表都被锁住。
很明显,临时表由于其固有特性,lock table 临时表实际是没有意义的,虽然不报错,但实际也被忽略的。
要锁住某张表的前提是要拥有表上select 权限。
lock table有如下两种表达方式:
lock table xxx read,只读方式锁住xxx,该表只能被select,不能被修改。如果在lock时,该表上存在事务,则lock语句挂起,直到事务结束。多个会话可以同时对表执行该操作。
lock table xxx write,读写方式锁住xxx,lock table的会话可以对表xxx做修改及查询等操作,而其他会话不能对该表做任何操作,包括select也要被阻塞。
可以同时锁住多个表。
授予ut01@%权限:
D:\temp>mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 38
Server version: 5.7.11-log MySQL Community Server (GPL)
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> drop user if exists 'ut01'@'%';
Query OK, 0 rows affected (0.09 sec)
mysql> drop user if exists 'ut02'@'%';
Query OK, 0 rows affected, 1 warning (0.05 sec)
mysql> show warnings;
+-------+------+---------------------------------+
| Level | Code | Message |
+-------+------+---------------------------------+
| Note | 3162 | User 'ut02'@'%' does not exist. |
+-------+------+---------------------------------+
1 row in set (0.00 sec)
mysql> create user 'ut01'@'%' identified by '20127163';
Query OK, 0 rows affected (0.08 sec)
mysql> show grants for 'ut01'@'%';
+----------------------------------+
| Grants for ut01@% |
+----------------------------------+
| GRANT USAGE ON *.* TO 'ut01'@'%' |
+----------------------------------+
1 row in set (0.00 sec)
mysql> grant lock tables on test.* to 'ut01'@'%';
Query OK, 0 rows affected (0.08 sec)
mysql> show grants for 'ut01'@'%';
+---------------------------------------------+
| Grants for ut01@% |
+---------------------------------------------+
| GRANT USAGE ON *.* TO 'ut01'@'%' |
| GRANT LOCK TABLES ON `test`.* TO 'ut01'@'%' |
+---------------------------------------------+
2 rows in set (0.00 sec)
mysql> grant select on test.* to 'ut01'@'%';
Query OK, 0 rows affected (0.05 sec)
mysql> select * from sys_menu;
+--------+--------------+-----------+
| menuId | menuParentId | menuUrlId |
+--------+--------------+-----------+
| 201 | 0 | 9001 |
| 202 | 201 | 9002 |
| 203 | 201 | 9003 |
| 204 | 202 | 9004 |
| 205 | 203 | 9005 |
| 206 | 204 | 9006 |
+--------+--------------+-----------+
6 rows in set (0.03 sec)
mysql> delete from sys_menu where menuid=201;
<hang....>
ERROR 1317 (70100): Query execution was interrupted
mysql>
mysql> select * from sys_menu;
+--------+--------------+-----------+
| menuId | menuParentId | menuUrlId |
+--------+--------------+-----------+
| 201 | 0 | 9001 |
| 202 | 201 | 9002 |
| 203 | 201 | 9003 |
| 204 | 202 | 9004 |
| 205 | 203 | 9005 |
| 206 | 204 | 9006 |
+--------+--------------+-----------+
6 rows in set (0.00 sec)
mysql>
该用户操作:
C:\Users\Administrator>mysql -u'ut01'
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 40
Server version: 5.7.11-log MySQL Community Server (GPL)
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> use test
Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| sys_menu |
| sys_role |
| sys_role_menu |
+----------------+
3 rows in set (0.00 sec)
mysql> lock table sys_menu read;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from sys_menu;
+--------+--------------+-----------+
| menuId | menuParentId | menuUrlId |
+--------+--------------+-----------+
| 201 | 0 | 9001 |
| 202 | 201 | 9002 |
| 203 | 201 | 9003 |
| 204 | 202 | 9004 |
| 205 | 203 | 9005 |
| 206 | 204 | 9006 |
+--------+--------------+-----------+
6 rows in set (0.00 sec)
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
mysql>
即使该用户有delete权限:
mysql> use test
Database changed
mysql> lock table sys_menu read;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from sys_menu where menuId=201;
ERROR 1099 (HY000): Table 'sys_menu' was locked with a READ lock and can't be updated
mysql>
使用lock table xxx read锁住表后,包括自己session在内的所有会话都不能修改表,只能select表。
另外,会话使用lock table方式锁住了某表之后,那么该会话只能操作(包括select)那些被锁住的表,其他表不能操作,直到unlock tables结束。
mysql> lock table sys_menu read;
Query OK, 0 rows affected (6.43 sec)
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| sys_menu |
| sys_role |
| sys_role_menu |
+----------------+
3 rows in set (0.00 sec)
mysql> select * from sys_role;
ERROR 1100 (HY000): Table 'sys_role' was not locked with LOCK TABLES
mysql> delete from sys_role where 1=1;
ERROR 1100 (HY000): Table 'sys_role' was not locked with LOCK TABLES
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
mysql> lock table sys_menu write;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from sys_role;
ERROR 1100 (HY000): Table 'sys_role' was not locked with LOCK TABLES
mysql> delete from sys_role where 1=1;
ERROR 1100 (HY000): Table 'sys_role' was not locked with LOCK TABLES
mysql>
在使用mysqldump导出数据时,默认会add-lcoks,比如:
C:\Users\Administrator>mysqldump --add-locks -B test > d:\temp\test.add-locks.sql
C:\Users\Administrator>
那么在bulk insert之前和之后有如下的lock语句:
LOCK TABLES `sys_menu` WRITE;
/*!40000 ALTER TABLE `sys_menu` DISABLE KEYS */;
#表示暂不维护索引,待插入完毕之后,再维护索引。但是由于InnoDB表的结构,所以该语句对于innodb表然并卵。
INSERT INTO `sys_menu` VALUES (201,0,9001),(202,201,9002),(203,201,9003),(204,202,9004),(205,203,9005),(206,204,9006),(207,201,9007),(208,202,9008);
/*!40000 ALTER TABLE `sys_menu` ENABLE KEYS */;
UNLOCK TABLES;
也可以通过如下方式禁用lock语句:
C:\Users\Administrator>mysqldump --skip-add-locks -B test > d:\temp\test.add-locks.sql
C:\Users\Administrator>
此时:
/*!40000 ALTER TABLE `sys_menu` DISABLE KEYS */;
INSERT INTO `sys_menu` VALUES (201,0,9001),(202,201,9002),(203,201,9003),(204,202,9004),(205,203,9005),(206,204,9006),(207,201,9007),(208,202,9008);
/*!40000 ALTER TABLE `sys_menu` ENABLE KEYS */;
lock tables的语句就没有了。
当然,如果有某个会话使用lock tables语句锁住了某个表,那么mysqldump在导出该表时也会hang住。
元数据锁
为了保证事务的可串行化。在一个事务中被操作(查询,修改等)的那些表,数据库必须保证其他会话不能修改这些表的表结构。
比如,一个会话执行了如下操作:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from sys_menu;
+--------+--------------+-----------+
| menuId | menuParentId | menuUrlId |
+--------+--------------+-----------+
| 201 | 0 | 9001 |
| 202 | 201 | 9002 |
| 203 | 201 | 9003 |
| 204 | 202 | 9004 |
| 205 | 203 | 9005 |
| 206 | 204 | 9006 |
| 207 | 201 | 9007 |
| 208 | 202 | 9008 |
+--------+--------------+-----------+
8 rows in set (5.92 sec)
mysql>
该会话显示开启了一个事务,并且select了一个表sys_menu。那么数据库会在这个表上保持“元数据锁”。以防止其他会话修改这个表的表结构。
比如,另一个会话执行:
mysql> use test
Database changed
mysql> ALTER TABLE `test`.`sys_menu`
-> DROP COLUMN `menuUrlId`;
<一直hang住,直到前面的会话结束事务>
这个会话不能执行的有ddl操作,以及lock table write操作。
相关文章推荐
- MySql学习笔记(1)-安装
- MySQL数据库连接报错,错误编号为10038
- Mysql To Charts(七)--效果show
- mysql my.ini配置文件修改无效
- mysql在表的某一位置增加一列、删除一列、修改列名
- Windows系统中MySQL 5.6的配置文件(my.ini)修改方法
- MySQL系列之一:数据库设计
- 微博的MySQL数据库优化实践经验
- MySQL—创建函数
- 关于配置环境报Cannot load JDBC driver class 'com.mysql.jdbc.Driver '
- 关于MySQL的卸载后重装(Cannot create Windows service for MySql等问题)
- 错误号码2003 Can't connect to MySQL server 'localhost' (0)
- MySQL数据库插入中文数据乱码问题
- 【the service mysql57 failed the most】
- MySQL enum用法--实现类似check的输入约束
- MySQL批量SQL插入性能优化
- MySQL通用优化手册
- MySQL索引类型总结和使用技巧以及注意事项
- mysql安装到最后一步无响应的问题解决
- Access denied for user 'root'@'' (using password:Y