LOCK TABLES
锁表语法
1 2 3 4 5 6 7 |
|
会话只能为自己获取、释放锁,不能为其他会话获取锁,也不能释放其他会话持有的锁。
LOCK TABLES
隐式的为当前会话获取表锁。表锁的对象可以是表也可以是视图。
获取视图锁时,LOCK TABLES
命令会自动锁定所有与该视图相关的基本表。
使用LOCK TABLES
显示的锁定一个表时,这个表的触发器中涉及到的表也会被隐式的锁定,锁的类型取决于触发器中对该表进行了何种操作。
表锁只是用来防止其他会话进行不恰当的操作,持有锁的会话,即使持有的仅仅是读锁,也可以进行诸如DROP TABLE
之类的表级操作。而由于TRUNCATE
操作不是事务安全的,所以在活动的事务或者持有表锁时尝试执行TRUNCATE
操作时会报错。
另外,虽然可以对临时表执行锁表操作,但是实际上会被自动忽略掉,不执行任何操作。因为临时表只对当前会话(也就是创建它的会话)是可见的。
锁的类型
READ [LOCAL]锁
- 持有读锁的会话可以读表,但是不能写表。
- 多个会话可以同时获得同一个表的读锁。
- 其他的会话不用获取该表的读锁也可以读取该表。
LOCAL
修饰符允许其他会话执行无冲突的插入语句。但是,如果是在服务器之外的进程上进行操作时,就不能使用READ LOCAL
了。另外,对于使用InnoDB引擎的表来说,READ LOCAL
与READ
没有任何区别。
[LOW_PRIORITY] WRITE锁
- 持有写锁的会话可以读表也可以写表。
- 只有持有写锁的会话可以访问该表。写锁释放前其他会话都不能对该表进行访问。
- 表被写锁锁定时,其他会话对该表的锁定请求将会被阻塞。
LOW_PRIORITY
修饰符已被弃用(当前版本为5.7)。直接使用WRITE
即可。
锁表语句会一直阻塞直到获取到所有需要的锁。 需要对表进行锁定的会话必须一次性的获取到所有它需要锁,因为一旦锁表语句执行完成,该会话就只能访问被锁的表了。
1 2 3 4 5 6 7 8 9 |
|
INFORMATION_SCHEMA
数据库中的表是个例外。即使有会话对这些表进行了锁定,其他会话依然可以继续访问。
在一条查询语句中无法多次对锁定的表使用同一个名字进行引用。这种情况下可以使用表的别名,并且对每一个别也要加一个锁:
1 2 3 4 |
|
不对表的别名进行锁定的话,就无法使用别名对该表进行访问:
1 2 3 |
|
相反,如果只对别名进行了锁定,则只能使用别名对其进行访问:
1 2 3 4 |
|
写锁通常相对读锁有更高的优先级,以确保更新操作尽快得到处理。这就意味着如果同时有写锁和读锁两个请求,那么写锁会先得到响应。LOCK TABLES
获取锁的过程如下:
- 使用内部定义的顺序对所有将被加锁的表进行排序,这一步对于用户来说是透明的。
- 如果一个表同时有读锁和写锁两个请求,将写锁请求放到读锁请求之前。
- 每次锁定一个表直到当前会话获取到所有的需要的锁,并保证不会产生死锁。
对分表进行锁定和解锁时,会锁定或者解锁整个表。
UNLOCK TABLES
解锁语法
1
|
|
使用UNLOCK TABLES
将显示的释放掉由当前会话持有的所有表锁。
LOCK TABLES
会在获取新锁之前隐式的释放掉当前会话持有的所有表锁。
会话开始一个事务(例如使用START TRANSACTION
)时,会隐式的执行UNLOCK TABLES
。
无论会话正常退出或者异常终止,服务器都会隐式的释放掉该会话持有的所有锁。客户端重新连接后,这些锁不会再生效。另外,如果客户端断开时正在执行一个事务,服务器会自动回滚该事务,客户端重连后,新会话将会自动设置为自动提交模式。因此,最好禁用客户端的auto-reconnec。在启用自动重连的情况下,重连后客户端其实已经丢失了所有的锁和事务,但是不会被通知。而当禁用掉自动重连时,一旦连接断开,在一个将被执行的语句处会报错。这样一来客户端就可以检测到这个错误,并采取适当的措施,比如重新获取需要的锁,重新执行之前的事务。
在被锁定的表上执行ALTER TABLE
语句后,将使该表变为未锁定状态。如果对该表再执行一条ALTER TABLE
语句,就会报错:Table ‘tbl_name’ was not locked with LOCK TABLES。这种情况下可以在执行完第一条ALTER TABLE
后,重新对该表进行锁定。
UNLOCK TABLES
还可以用来释放之前通过FLUSH TABLES WITH READ LOCK
获得的全局读锁。