[转帖]mysql表锁与lock tables_MySQL, Oracle及数据库讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  MySQL, Oracle及数据库讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 1992 | 回复: 0   主题: [转帖]mysql表锁与lock tables        下一篇 
无止境
注册用户
等级:新兵
经验:64
发帖:74
精华:0
注册:2011-11-14
状态:离线
发送短消息息给无止境 加好友    发送短消息息给无止境 发消息
发表于: IP:您无权察看 2014-11-12 10:32:19 | [全部帖] [楼主帖] 楼主

对于MyISAM/Memory/Merge等引擎,mysql只提供表级锁,分为读锁和写锁,可通过lock tables手工获取,而DML会自动获取写锁;

下面着重介绍lock tables的用法

所需权限

用户必须拥有lock tables和select权限;

选项

Read [local]—可由多个会话同时获取,local用于MyISAM,允许并发插入

[low_priority] write—阻止其他会话访问该表,通常写锁比读锁优先级要高,如果某表已经被添加读锁,此时其他会话申请写锁,则所有后续读锁请求会阻塞直至写锁释放,这样会影响读锁并发;

而low_priority则允许其他读锁优先执行,使用该选项必须谨慎,很容易导致写锁饥饿等待;

对于autocommit=0的innodb表,low_priority选项无效,视为普通写锁,会导致后续读锁请求等待

算法

1 对候选基表采用内部算法排序,用户无法干预此行为

2 如果表同时请求读锁和写锁,优先处理写锁,除非使用了low_priority,但此选项对开启事务的innodb无效

3 一次只锁定一个表,但释放时同时执行

释放表锁

1  调用unlock tables,必须由执行Lock tables的同一会话执行

2  若会话再次调用lock tables,则其原本获取到的锁会被隐式释放

3   开启事务会隐含调用unlock tables,诸如start transaction

4   占有锁的会话一旦终止其锁会被自动释放,事务也会被回滚

5   rollback不会释放表锁

表锁的限制

可用于锁定视图,即锁定该视图所有基表;

表锁仅阻止其他会话进行读写操作,若当前会话拥有某个表的锁,可执行drop table,但不可执行truncate table;

当对表进行insert delayed时不可对其添加表锁,否则insert delayed会报错,只因该insert由一个单独线程操作;

所有的单个update语句会默认获取表锁;

如要对一系列MyISAM表进行大量操作,可提前锁定表以提升性能,因为Mysql对加锁的表不会刷新其key cache;

默认写锁优先级较高,但可通过low_priority_updates/max_write_lock_count/high_priority等手段提升读锁优先级,也可修改mysys/thr_lock代码只使用一个队列,让写锁/读锁拥有相同优先级;

对于非事务引擎表,因为不支持select … for update,必须先锁定表,然后查询并更新

LOCK TABLES trans READ, customer WRITE;
SELECT SUM(value) FROM trans WHERE customer_id=some_id;
UPDATE customer
SET total_value=sum_from_previous_statement
WHERE customer_id=some_id;
UNLOCK TABLES


必须一次锁定所有要访问的表,否则会抱错,而information_schema下的表不需要显示锁定也可访问

mysql> LOCK TABLES t1 READ;
mysql> SELECT COUNT(*) FROM t1;
+----------+
| COUNT(*) |
+----------+
|        3 |
+----------+
mysql> SELECT COUNT(*) FROM t2;
ERROR 1100 (HY000): Table 't2' was not locked with LOCK TABLES


不能在一条sql中引用2次被锁定的表,即便使用也必须改用alias别名

mysql> LOCK TABLE t WRITE, t AS t1 READ;
mysql> INSERT INTO t SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> INSERT INTO t SELECT * FROM t AS t1


表锁与事务

Lock tables会隐式提交当前事务,unlock tables只有在已经调用lock tables的前提下才会隐式commit;

开启事务(诸如start transaction)会释放当前获取的表锁;

Flush tables with read lock获取的是全局锁,而非表锁;

表锁与InnoDB

对于Innodb表,若要使用表锁,必须先设置autocommit=0且innodb_table_locks=1(默认),否则InnoDB无法侦测表锁而Mysql也无法感知行锁的存在;

且在事务提交后再unlock tables,如下例所示:

调用lock tables时,innodb引擎会获取内部表锁,然后mysql服务器获取表锁;commit时innodb释放内部表锁,unlock tables时mysql服务器才释放表锁;

如果autocommit=1,innodb不会获取内部表锁,极易导致死锁发生;

SET autocommit=0;
LOCK TABLES t1 WRITE, t2 READ, ...;... do something with tables t1 and t2 here ...
COMMIT;
UNLOCK TABLES


Lock tables与触发器

如果基表上建有触发器,且触发器引用到了其他表,则锁定基表时会连带锁定这些被引用的表

LOCK TABLES t1 WRITE, t2 READ;
CREATE TRIGGER t1_a_ins AFTER INSERT ON t1 FOR EACH ROW
BEGIN
UPDATE t4 SET count = count+1
WHERE id = NEW.id AND EXISTS (SELECT a FROM t3);
INSERT INTO t2 VALUES(1, 2);
END;
--t1添加写锁
--t2 添加写锁,即便是申请的读锁,因为在trigger有insert操作,故被转换为写锁
--t3读锁
--t4写锁


表锁与分区表

对于MyISAM引擎,DML和lock tables会锁定整个分区表,create view/alter table只会锁住使用的分区,5.6.6引入了partition lock prunning改善了此功能;

而InnoDB,在分区修剪前不会实施行级锁,故不存在锁定整个分区的问题;

表锁统计信息

mysql> SHOW STATUS LIKE 'Table%';
+-----------------------+---------+
| Variable_name         | Value   |
+-----------------------+---------+
| Table_locks_immediate | 1151552 |
| Table_locks_waited    | 15324   |
+-----------------------+---------+!~~


--转自 北京联动北方科技有限公司




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论