思路话语

。Arlen:思想有多远你就能走多远...

锁的调试

锁等待可能发生在mysql服务器上也可能发生在存储引擎中。

mysqlserver上的锁:

1.表锁:有显式也有隐式的。

显式:

使用lock tables创建的就是显式锁,如lock tables tableA read/write

可通过show processlist\G查看那些在等待着的线程:

**********1.row****

id:11

user:arlen

Host:localhost

...

State:Locked

Info:LOCK TABLES tableA Write

只有这一种方式会让线程进入Locked状态:当它试图获取一个表锁的时候,已经有另外的线程占有了这个表锁。

因此,当你看到这个信息时,就能知道线程等待的是mysql服务器里的锁,而不是存储引擎里的。

 

隐式:

服务器会在查询时隐含的锁定表。展示隐式锁的一个最简单的办法就是运行一个耗时很长的查询,这个在select中加一个sleep函数就可以很轻易的做到:

select sleep(30) from tableA ;

当查询正在运行时,如果你再次尝试去锁定tableA,这个操作就会因为隐式锁的存在而挂起,就象有显式锁的时候那样。

 

隐含读锁会阻塞lock tables这类显式的写锁,同样,隐含锁之间也会相互阻塞。

你大概会迷惑于显式锁和隐式锁的区别,

对于myisam这类存储引擎,锁是由服务器实现,所以,从内部原理上来讲,显式锁和隐式锁是同一类型的锁,都是服务器代码在控制它们;从外部行为上来讲,你可以用lock tables和unlock tables来控制显式锁。

但对于innodb,你显式的创建锁它会完成你想让它做的事情,但隐式锁就是隐藏的,服务器会根据需要自动创建和释放隐含锁,它告诉存储引擎这些锁的存在,存储引擎转换出合适的锁。在innodb中就有关于为指定的服务器级表锁创建哪种innodb表锁的规则。这样就很难了解到innodb在幕后到底创建了什么样的锁。

 

通过show process list 只可以看到谁在等待锁,但通过mysqladmin debug就可以找出谁持有了表锁:

该输出在末尾的地方,会看到类似如下信息:

Thread database.table_name Locked/Waiting  Lock_type

7 sch.tablea   locked-read  Read lock without concurent insert

8 sch.tablea   waiting-write  Highest  priority write lock

可以看出,id=8的线程正在等待7号线程持有的锁

(注:mysqladmin debug会输出很多信息,但和锁相关的就这些)

 

2.全局锁:只有一个语句能产生全局锁,就是flush tables with read lock

flush tables with read lock;

lock tables database.tableA write;//此请求会挂起

show processlist\G

********2. row***

Id:22

User:..

State:Waiting for release of deadlock

Info:lock tables database.tableA write

请注意这个查询的状态是waiting一个死锁的释放,这说明该锁等待的是全局读锁,而非表级锁。

目前mysql没有办法找出谁持有这个全局锁。

 

3.名称锁:当服务器重命名或者删除一个表时创建的一种表锁。

lock tables *** with read;

rename table database1.tableA to database1.tableB;

show processlist;

******1***

...

State:Waiting for table

Info:rename table database1.tableA to database1.tableB.

也可以通过show open tables的信息列name_locked看到:

database    table in_use  name_locked

database1  tableC  1  0

database1  tableA  1  1

database1   tableB 2  1

 

同样,可以通过mysqladmin debug来看到这个名称锁是在等待哪一个普通的表锁。

 

4.字符串锁:可用get lock()和其它相关函数来锁定和释放任何一个服务器范围内的字符串

也叫用户锁,user locks.。是基于命名互斥量来实现的,你可以指定一个字符串,然后试着去锁定,并在超时之前获取到它的锁。

select get_lock('mylock', 100);

成功获取锁后,如果还有其它线程要获取同一个串的锁,就会被挂起,直到超时,如select get_lock('mylock', 200);

show processlist\G;

....

State:User lock

Info:select get_lock('mylock', 200);

mysql没有提供找出谁持有了某个用户锁的方法。

 

Innodb中的锁等待

可以通过show innodb status中看到谁在等待锁,那么如何找出哪个事务占用了锁呢?

1. 可以通过create table innodb_lock_monitor(a int) engine=innodb;激活锁监控器。

此时可以在服务器的错误日志信息中看到哪些事务在某个表上有个什么样的锁。

激活后,也可以再次通过show innodb status来看,此时也会有这个锁信息。

锁监控器的输出是没有经过优化的,问题信息非常冗长,很容易就会填满错误日志,show innodb status也会很容易的就被它填到溢出。

针对这个情况,我们可以进一步使用innotop来看,它的lock模式能够显示锁信息。并通过连接和表优美的结合在一起,你能很快看出哪一个事务霸占着指定表上的锁。

2.innodb的开发者正在打算将事务信息输出到information_schema中,可能在未来的版本中就能方便的查看这类锁信息了,拭目以待吧。

 

 注:今天看了下innodb的官方,发现它们已经有锁的调试功能了,但是需要额外安装一个innodb plugin。

The seven INFORMATION_SCHEMA tables INNODB_CMP, INNODB_CMP_RESET, INNODB_CMPMEM, INNODB_CMPMEM_RESET, INNODB_TRX, INNODB_LOCKS and INNODB_LOCK_WAITS contain live information about compressed InnoDB tables, the compressed InnoDB buffer pool, all transactions currently executing inside InnoDB, the locks that transactions hold and those that are blocking transactions waiting for access to a resource (a table or row).

Note that the Information Schema tables are themselves plugins to the MySQL server. As such they need to be INSTALLed as described in Chapter 9, Installing the InnoDB Plugin. If they are installed, but the InnoDB storage engine plugin is not installed, these tables appear to be empty.

from:http://www.innodb.com/doc/innodb_plugin-1.0/innodb-information-schema.html#innodb-information-schema-innodb_locks

innodb plugin的安装:

 http://www.orczhou.com/index.php/2010/03/innodb-plugin-setup/

 

posted on 2010-06-15 14:21  Arlen  阅读(296)  评论(0编辑  收藏  举报

导航