MySQL中lock tables和unlock tables浅析

MySQL中lock tables和unlock tables浅析

 

在MySQL中提供了锁定表(lock tables)和解锁表(unlock tables)的语法功能,ORACLE与SQL Server数据库当中没有这种语法。相信刚接触MySQL的人,都想详细、深入的了解一下这个功能.下面就尽量全面的解析、总结一下MySQL中lock tables与unlock tables的功能,如有不足或不正确的地方,欢迎指点一二。

 

 

锁定表的语法:

 

LOCK TABLES

tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE}

[, tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE}] ...

 

 

 LOCAL修饰符表示可以允许在其他会话中对在当前会话中获取了READ锁的的表执行插入。但是当保持锁时,若使用Server外的会话来操纵数据库则不能使用READ LOCAL。另外,对于InnoDB表,READ LOCAL与READ相同。

 

The LOCAL modifier enables nonconflicting INSERT statements (concurrent inserts) by other sessions to execute while the lock is held. (See Section 8.11.3, “Concurrent Inserts”.) However, READ LOCAL cannot be used if you are going to manipulate the database using processes external to the server while you hold the lock. For InnoDB tables, READ LOCAL is the same as READ.

 

修饰符LOW_PRIORITY用于之前版本的MySQL,它会影响锁定行为,但是从MySQL 5.6.5以后,这个修饰符已经被弃用。如果使用它则会产生警告。

 

 

[LOW_PRIORITY] WRITE lock:

 

The session that holds the lock can read and write the table.

 

Only the session that holds the lock can access the table. No other session can access it until the lock is released.

 

Lock requests for the table by other sessions block while the WRITE lock is held.

 

The LOW_PRIORITY modifier has no effect. In previous versions of MySQL, it affected locking behavior, but this is no longer true. As of MySQL 5.6.5, it is deprecated and its use produces a warning. Use WRITE without LOW_PRIORITY instead.

 

 

解锁表的语法:

 

UNLOCK TABLES

 

 

LOCK TABLES为当前会话锁定表。 UNLOCK TABLES释放被当前会话持有的任何锁。官方文档“13.3.5 LOCK TABLES and UNLOCK TABLES Syntax”已经对LOCK TALES与UNLOCK  TABLES做了不少介绍,下面我们通过一些测试例子来深入的理解一下锁表与解锁表的相关知识点。我们先准备一下测试环境用的表和数据。

 

mysql> create table test( id int, name varchar(12));
Query OK, 0 rows affected (0.07 sec)
 
mysql> insert into test
    -> select 10001, 'kerry'   union all
    -> select 10002, 'richard' union all
    -> select 10003, 'jimmy' ;
Query OK, 3 rows affected (0.05 sec)
Records: 3  Duplicates: 0  Warnings: 0
 
mysql> 

 

当前会话(会话ID为61)持有test表的READ锁后,那么当前会话只可以读该表,而不能往表中写入数据,否则就会报“Table 'test' was locked with a READ lock and can't be updated”这样的错误。

 

mysql> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
|              61 |
+-----------------+
1 row in set (0.00 sec)
 
mysql> show open tables where in_use >=1;
Empty set (0.00 sec)
 
mysql> lock tables test read;
Query OK, 0 rows affected (0.00 sec)
 
mysql> show open tables where in_use >=1;
+----------+-------+--------+-------------+
| Database | Table | In_use | Name_locked |
+----------+-------+--------+-------------+
| MyDB     | test  |      1 |           0 |
+----------+-------+--------+-------------+
1 row in set (0.01 sec)
 
mysql> select * from test;
+-------+---------+
| id    | name    |
+-------+---------+
| 10001 | kerry   |
| 10002 | richard |
| 10003 | jimmy   |
+-------+---------+
3 rows in set (0.00 sec)
 
mysql> insert into test
    -> values(10004, 'ken');
ERROR 1099 (HY000): Table 'test' was locked with a READ lock and can't be updated
mysql> 

 

 

 

 

另外,我们测试一下修饰符LOCAL的用途,如下所示:

 

mysql> create table test2( id int , name varchar(12)) engine=MyISAM;
Query OK, 0 rows affected (0.05 sec)
 
mysql> insert into test2
    -> select 1001, 'test';
Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0
mysql> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
|              66 |
+-----------------+
1 row in set (0.00 sec)
 
mysql> lock tables test2 read local;
Query OK, 0 rows affected (0.00 sec)
 
mysql> select * from test2;
+------+------+
| id   | name |
+------+------+
| 1001 | test |
+------+------+
1 row in set (0.00 sec)
 
mysql> insert into test2
    -> select 1002, 'kkk';
ERROR 1099 (HY000): Table 'test2' was locked with a READ lock and can't be updated
mysql> 

 

在其它会话当中,你可以看到表test2可以被插入。当然前提是表的存储引擎不能是InnoDB引擎,否则使用修饰符LOCAL和不用LOCAL是一样的,其它会话无法对表写入。

 

mysql> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
|              65 |
+-----------------+
1 row in set (0.00 sec)
 
mysql> select * from test2;
+------+------+
| id   | name |
+------+------+
| 1001 | test |
+------+------+
1 row in set (0.00 sec)
 
mysql> insert into test2
    -> select 1002, 'kkk';
Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

 

那么其他会话是否也能读此表呢?  其它会话能否也能锁定该表(LOCK TABLES READ)? 其它会话是否也能锁定该表呢?(LOCK TABLES WRITE)

 

mysql> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
|              62 |
+-----------------+
1 row in set (0.01 sec)
 
mysql> select * from test;
+-------+---------+
| id    | name    |
+-------+---------+
| 10001 | kerry   |
| 10002 | richard |
| 10003 | jimmy   |
+-------+---------+
3 rows in set (0.00 sec)
 
mysql> lock tables test read;
Query OK, 0 rows affected (0.00 sec)
 
mysql> show open tables where in_use >=1;
+----------+-------+--------+-------------+
| Database | Table | In_use | Name_locked |
+----------+-------+--------+-------------+
| MyDB     | test  |      2 |           0 |
+----------+-------+--------+-------------+
1 row in set (0.00 sec)
 
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
 
mysql> show open tables where in_use >=1;
+----------+-------+--------+-------------+
| Database | Table | In_use | Name_locked |
+----------+-------+--------+-------------+
| MyDB     | test  |      1 |           0 |
+----------+-------+--------+-------------+
1 row in set (0.00 sec)
 
mysql> lock tables test write;

 

 

 

 

如上测试所示,如果一个会话在一个表上获得一个READ锁后,该会话和所有其他会话只能从表中读。不能往表中写,其它会话也可在该表获取一个READ锁,此时你会在show open tables里面看到in_use的值增加。其实LOCK TABLES READ是一个表锁,而且是共享锁。但是当一个会话获取一个表上的READ锁后,其它会话就不能获取该表的WRITE锁了,此时就会被阻塞,直到持有READ锁的会话释放READ锁。

 

 

 

另外需要注意的是,当前会话如果锁定了其中一个表,那么是无法查询其它表的。否则会报“ERROR 1100 (HY000): Table 'worklog' was not locked with LOCK TABLES”错误。

 

 

 

那么我们再来看看WRITE锁吧。测试前,先在上面两个会话中执行 unlock tables命令。然后获得表TEST上的一个WRITE锁,如下所示,当前会话可以读写表TEST

 

mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
 
mysql> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
|              61 |
+-----------------+
1 row in set (0.00 sec)
 
mysql> show open tables where in_use >=1;
Empty set (0.00 sec)
 
mysql> lock tables test write;
Query OK, 0 rows affected (0.00 sec)
 
mysql> select * from test;
+-------+---------+
| id    | name    |
+-------+---------+
| 10001 | kerry   |
| 10002 | richard |
| 10003 | jimmy   |
+-------+---------+
3 rows in set (0.00 sec)
 
mysql> update test set name='ken' where id=10003;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0
 
mysql> 

 

其它会话无法读写表TEST,都会被阻塞,当然也无法获取表TEST的READ锁或WRITE锁。也就是说当一个会话获得一个表上的一个WRITE锁后,那么只有持锁的会话READ或WRITE表,其他会话都会被阻止。

 

mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
 
mysql> 
mysql> 
mysql> show open tables where in_use >=1;
+----------+-------+--------+-------------+
| Database | Table | In_use | Name_locked |
+----------+-------+--------+-------------+
| MyDB     | test  |      1 |           0 |
+----------+-------+--------+-------------+
1 row in set (0.00 sec)
 
mysql> select * from test;

 

 

 

 

mysql> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
|              63 |
+-----------------+
1 row in set (0.00 sec)
 
mysql> show processlist;
+----+------+-----------+------+---------+------+---------------------------------+--------------------+
| Id | User | Host      | db   | Command | Time | State                           | Info               |
+----+------+-----------+------+---------+------+---------------------------------+--------------------+
| 61 | root | localhost | MyDB | Sleep   |   86 |                                 | NULL               |
| 62 | root | localhost | MyDB | Query   |   40 | Waiting for table metadata lock | select * from test |
| 63 | root | localhost | MyDB | Query   |    0 | init                            | show processlist   |
| 64 | root | localhost | MyDB | Sleep   | 2551 |                                 | NULL               |
+----+------+-----------+------+---------+------+---------------------------------+--------------------+
4 rows in set (0.00 sec)

 

 

UNLOCK TABLES释放被当前会话持有的任何锁,但是当会话发出另外一个LOCK TABLES时,或当服务器的连接被关闭时,当前会话锁定的所有表会隐式被解锁。下面我们也可以测试看看

 

mysql> lock tables test read;
Query OK, 0 rows affected (0.00 sec)
 
mysql> show open tables where in_use >=1;
+----------+-------+--------+-------------+
| Database | Table | In_use | Name_locked |
+----------+-------+--------+-------------+
| MyDB     | test  |      1 |           0 |
+----------+-------+--------+-------------+
1 row in set (0.00 sec)
 
mysql> lock tables worklog read;
Query OK, 0 rows affected (0.00 sec)
 
mysql> show open tables where in_use >=1;
+----------+---------+--------+-------------+
| Database | Table   | In_use | Name_locked |
+----------+---------+--------+-------------+
| MyDB     | worklog |      1 |           0 |
+----------+---------+--------+-------------+
1 row in set (0.00 sec)
 
mysql> 

 

 

那么我们如何在当前会话锁定多个表呢?如下所示:

 

 

mysql> show open tables where in_use >=1;
Empty set (0.00 sec)
 
mysql> lock tables test read, worklog read;
Query OK, 0 rows affected (0.00 sec)
 
mysql> show open tables where in_use >=1;
+----------+---------+--------+-------------+
| Database | Table   | In_use | Name_locked |
+----------+---------+--------+-------------+
| MyDB     | worklog |      1 |           0 |
| MyDB     | test    |      1 |           0 |
+----------+---------+--------+-------------+
2 rows in set (0.00 sec)
 
mysql> 

 

 

 

另外,还有一些细节问题,LOCK TABLES是否可以为视图、触发器、临时表加锁呢?

 

 

mysql> create table test2( id int, sex bit);
Query OK, 0 rows affected (0.06 sec)
 
mysql> insert into test2
    -> select 10001, 1 union all
    -> select 10002, 0 union all
    -> select 10003, 1;
Query OK, 3 rows affected (0.02 sec)
Records: 3  Duplicates: 0  Warnings: 0
mysql> create view v_test
    -> as
    -> select t1.id, t1.name, t2.sex
    -> from test t1 left join test2 t2 on t1.id =t2.id;
Query OK, 0 rows affected (0.01 sec)
mysql> lock tables v_test read;
Query OK, 0 rows affected (0.00 sec)
 
mysql> show open tables where in_use >=1;
+----------+-------+--------+-------------+
| Database | Table | In_use | Name_locked |
+----------+-------+--------+-------------+
| MyDB     | test2 |      1 |           0 |
| MyDB     | test  |      1 |           0 |
+----------+-------+--------+-------------+
2 rows in set (0.00 sec)
 
mysql> 

 

 

 

如上测试所示,对于VIEW加锁,LOCK TABLES语句会为VIEW中使用的所有基表加锁。对触发器使用LOCK TABLE,那么就会锁定触发器中所包含的全部表(any tables used in triggers are also locked implicitly)

 

 

mysql> unlock tables;

Query OK, 0 rows affected (0.00 sec)

 

mysql> create temporary table tmp like test;

Query OK, 0 rows affected (0.04 sec)

 

mysql> show open tables where in_use >=1;

Empty set (0.00 sec)

 

mysql> select database();

+------------+

| database() |

+------------+

| MyDB       |

+------------+

1 row in set (0.00 sec)

 

mysql> select * from tmp;

Empty set (0.00 sec)

 

mysql> insert into tmp

    -> select 1001, 'kerry' ;

Query OK, 1 row affected (0.01 sec)

Records: 1  Duplicates: 0  Warnings: 0

 

mysql>

 

LOCK TABLES 与 UNLOCK TABLES只能为自己获取锁和释放锁,不能为其他会话获取锁,也不能释放由其他会话保持的锁。一个对象获取锁,需具备该对象上的SELECT权限和LOCK TABLES权限。LOCK TABLES语句为当前会话显式的获取表锁。最后,关于LOCK TABLES与事务当中锁有那些异同,可以参考官方文档13.3.5.1 Interaction of Table Locking and Transactions

 

LOCK TABLES and UNLOCK TABLES interact with the use of transactions as follows:

 

 

·         LOCK TABLES is not transaction-safe and implicitly commits any active transaction before attempting to lock the tables.

 

 

·         UNLOCK TABLES implicitly commits any active transaction, but only if LOCK TABLES has been used to acquire table locks. For example, in the following set of statements,UNLOCK TABLES releases the global read lock but does not commit the transaction because no table locks are in effect:

 

 

时间: 2024-10-19 05:40:44

MySQL中lock tables和unlock tables浅析的相关文章

mysql中lock tables与unlock tables(锁表/解锁)使用总结

php mysql lock tables 使用有感 mysql 的 表锁 lock tables 感觉就像一个 封闭的空间 mysql发现 lock tables 命令的时候,会将带有锁标记的表(table) 带入封闭空间,直到 出现 unlock tables 命令 或 线程结束, 才关闭封闭空间. 进入封闭空间时 , 仅仅只有锁标记的表(table) 可以在里面使用,其他表无法使用. 锁标记 分为 read 和 write 下面是 两种 锁的区别 ---------------------

MySQL的lock tables和unlock tables使用详解

lock tables 命令是为当前线程锁定表.这里有2种类型的锁定,一种是读锁定,用命令 lock tables tablename read;另外一种是写锁定,用命令lock tables tablename write.下边分别介绍: 1. lock table 读锁定 如果一个线程获得在一个表上的read锁,那么该线程和所有其他线程只能从表中读数据,不能进行任何写操作. 下边我们测试下,测试表为user表. 不同的线程,可以通过开多个命令行MySQL客户端来实现: 时刻点  线程A(命令

mysql中mysqlhotcopy热备份例子

备份特点: 一个快速文件意义上的COPY,只能运行在数据库目录所在的机器上,在线执行LOCK TABLES 以及 UNLOCK TABLES,恢复时只需要COPY备份文件到源目录覆盖即可. 不足:备份时不能会锁表,不能进行数据更新或插入,备份只能局限于本机. 使用前机器需具备perl 环境并安装perl-DBD包 MYSQLHOTCOPY用法: 1).mysqlhotcopy 原数据库名,新数据库名 2).mysqlhotcopy 原数据库名,备份的目录 3).也可以使用下面的脚本 #!/bin

mysql中update的low_priority

low_priority,低优先级 UPDATE [LOW_PRIORITY] tbl_name SET col_name1=expr1,col_name2=expr2,- mysql中update用low_priority让update不锁定表 MySQL允许你改变语句调度的优先级,它可以使来自多个客户端的查询更好地协作,这样单个客户端就不会由于锁定而等待很长时间.改变优先级还可以确保特定类型的查询被处理得更快.这一部分讲解MySQL的默认的调度策略和可以用来影响这些策略的选项.它还谈到了并发

mysql中mysqlhotcopy备份使用说明

1安装.mysql已经安装好,在/usr/local/mysql目录下  代码如下 复制代码 yum -y install perl perl-DBI wget http://file.111cn.net/upload/2013/12/DBD-mysql-3.0002.tar.gz tar zxvf  DBD-mysql-3.0002.tar.gz cd DBD-mysql-3.0002 perl Makefile.PL  –mysql_config=/usr/local/mysql/bin/m

MySQL中的SQL特征

  为了与MySQL服务器进行通信,必须熟练掌握SQL.例如,在使用诸如mysql客户机这样的程序时,其功能首先是作为一种发送SQL 语句给服务器执行的工具.而且,如果编写使用编程语言所提供的MySQL接口的程序时,也必须熟悉SQL 语言,因为需要发送SQL 语句与服务器沟通.    第1章"MySQL与SQL介绍"的教程介绍了许多MySQL功能.本章在该教程的基础上进一步对MySQL的SQL的几个方面进行研究.它讨论了怎样引用数据库的要素,包括命名规则以及区分大小写约束的适用性.它还

PHP 中执行排序与 MySQL 中排序_php技巧

此文首发在 InfoQ 中文站.作者:明灵(dragon) , Fenng . Note:要转载的朋友请注意注明这篇文章的第一作者!这篇文章是dragon 朋友来邮探讨后他做的一个总结.在 DB 中排序还是在 应用程序中排序是个很有趣的话题,dragon 第一份邮件中其实已经总结的很好了,我添加了一点建议而已.现在放上来,与大家共享.这篇文章也投稿到了 InfoQ 中文站 . Q:列出在 PHP 中执行排序要优于在 MYSQL 中排序的原因?给一些必须在MYSQL中排序的实例? A:通常来说,执

MYSQL中一个特殊的MDL LOCK死锁案列

水平有限 如有错误请指出共同探讨 版本:5.7.19 mysql+innodb 本文中所说的上文是如下文章,也是讨论MDL LOCK死锁的基础,包含了很多MDL LOCK的基础知识建议 好好阅读http://blog.itpub.net/7728585/viewspace-2143093/ 一.问题由来 前段开发反馈时间线上数据库老是出现死锁情况,而我们设置了innodb_print_all_deadlocks,但是在 相应的时间点没有找到任何相应的死锁的信息,从而导致我们获得任何有用的信息,也

浅析MySQL中的Index Condition Pushdown (ICP 索引条件下推)和Multi-Range Read(MRR 索引多范围查找)查询优化

原文:浅析MySQL中的Index Condition Pushdown (ICP 索引条件下推)和Multi-Range Read(MRR 索引多范围查找)查询优化   本文出处:http://www.cnblogs.com/wy123/p/7374078.html(保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错误进行修正或补充,无他)     ICP优化原理 Index Condition Pushdown (ICP),也称为索引条件下推