MySQL的表锁问题(一)

来源:互联网 发布:华小夏汉服淘宝 编辑:程序博客网 时间:2024/05/18 02:58

在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表和它的别名t1
mysql> INSERT INTO t SELECT * FROM t;#此时使用了2次t表
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> 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 TABLES
mysql> 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 a MyISAM table has no holes in the data file (deleted rows in the middle), an INSERT statement can be executed to add rows to 
the end of the table at the same time that SELECT statements are reading rows from the table. If there are multiple INSERT 
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 表示学要经过等待才能获取表所的次数

0 0
原创粉丝点击