在mysql手册里面有一段描述关于lock tables的语法的.
LOCK TABLES
tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE}
[, tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE}] ...
UNLOCK TABLES
READ
当表不存在 WRITE 写锁时 READ 读锁被执行,这该状态下,当前线程不可以修改(insert,update,delete),其他线程的修改操作进入列队,当当前线程释放锁,其他线程修改被执行.
READ LOCAL
READ LOCAL和READ之间的区别是,READ LOCAL允许在锁定被保持时,执行非冲突性INSERT语句(同时插入)。但是,如果您正打算在MySQL外面操作数据库文件,同时您保持锁定,则不能使用READ LOCAL。对于InnoDB表,READ LOCAL与READ相同。
WRITE
除了当前用户被允许读取和修改被锁表外,其他用户的所有访问被完全阻止。注意的是在当前线程当WRITE被执行的时候,即使之前加了READ没被取消,也会被取消.
LOW_PRIORITY WRITE
降低优先级的WRITE,默认WRITE的优先级高于READ.假如当前线程的LOW_PRIORITY WRITE在列队里面,在未执行之前其他线程传送一条READ,那么LOW_PRIORITY WRITE继续等待.
当您使用LOCK TABLES时,您必须锁定您打算在查询中使用的所有的表。虽然使用LOCK TABLES语句获得的锁定仍然有效,但是您不能访问没有被此语句锁定的任何的表。同时,您不能在一次查询中多次使用一个已锁定的表——使用别名代替,在此情况下,您必须分别获得对每个别名的锁定。
手册给出了如下的例子:
mysql> LOCK TABLE t WRITE, t AS t1 WRITE;#此时锁定的应该算是t表和它的别名t1mysql> INSERT INTO t SELECT * FROM t;#此时使用了2次t表ERROR 1100: Table 't' was not locked with LOCK TABLESmysql> INSERT INTO t SELECT * FROM t AS t1;
mysql> LOCK TABLE t READ;mysql> SELECT * FROM t AS myalias;#因为不能访问没有被语句锁定的任何的表,应该算吧别名myalias算作表了ERROR 1100: Table 'myalias' was not locked with LOCK TABLES
mysql> LOCK TABLE t AS myalias READ;mysql> SELECT * FROM t;#道理和上面类似ERROR 1100: Table 't' was not locked with LOCK TABLESmysql> SELECT * FROM t AS myalias;
LOCK TABLES按照如下方式执行:
1. 按照内部定义的顺序,对所有要被锁定的表进行分类。从用户的角度,此顺序是未经定义的。
2. 如果使用一个读取和一个写入锁定对一个表进行锁定,则把写入锁定放在读取锁定之前。
3. 一次锁定一个表,直到线程得到所有锁定为止。
注意,您不能使用INSERT DELAYED锁定任何您正在使用的表,因为,在这种情况下,INSERT由另一个线程执行。有些MyISAM操作在LOCK TABLES之下更快的原因是,MySQL不会清空用于已锁定表的关键缓存,直到UNLOCK TABLE被调用为止。通常,关键缓存在每个SQL语句之后被清空。另外MyISAM还支持Concurrent Inserts,直译就是并发的插入.
看了上面大家都会以为MyISAM是完全的相互独立且阻塞的,没有并发处理的能力,其实不然.
MyISAM有个非常重要的特性就是Concurrent Inserts
在my.cnf里面可以设置Concurrent Inserts的值,默认为1
具体如下:
concurrent inserts=1,如果数据文件中没有因为delete或update产生的空洞,那么在处理select语句的同时可以执行insert操作,并把数据插到表的最后,如果
有多条insert那么将列队进行.
英文原文如下:
If aMyISAM
table has no holes in the data file (deleted rows in the middle), anINSERT
statement can be executed to add rows to
the end of the table at the same time thatSELECT
statements are reading rows from the table. If there are multipleINSERT
statements, they are queued and performed in sequence, concurrently with the SELECT
statements.
注:原文并没有update,仅有deleted rows in the middle之所我加上,某些情况下text字段类型所在行被清空或被删除都会产生数据空洞,另此处未提到的是,当这些
空洞被修复之后,那么Concurrent Inserts有自动可以进行了)
concurrent inserts=0,不管有没有数据空洞,Concurrent Inserts都会被禁止.
concurrent inserts=2,不管有没有数据空洞,Concurrent Inserts都会被执行.
在binarylog里面Concurrent Inserts会被转换成普通的insert操作
懒得翻译摘几个说明:
With LOAD DATA INFILE
, if you specify CONCURRENT
with a MyISAM
table that satisfies the condition for concurrent inserts (that is, it contains no free blocks in the middle), other sessions can retrieve data from the table while LOAD DATA
is executing. Use of the CONCURRENT
option affects the performance of LOAD DATA
a bit, even if no other session is using the table at the same time.
If you specify HIGH_PRIORITY
, it overrides the effect of the --low-priority-updates
option if the server was started with that option. It also causes concurrent inserts not to be used.
For LOCK TABLE
, the difference between READ LOCAL
and READ
is that READ LOCAL
allows nonconflicting INSERT
statements (concurrent inserts) to execute while the lock is held. However, this cannot be used if you are going to manipulate the database using processes external to the server while you hold the lock
可以使用
mysql> show status like "table_lock%";
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Table_locks_immediate | 81204 |
| Table_locks_waited | 2128 |
查看mysql的表锁争用情况
Table_locks_immediate表示不经过等待立即获取表锁的次数.
Table_locks_waited 表示学要经过等待才能获取表所的次数