是否可以锁定一个表,使持有者可以读写,而其他会话仅能读取?
根据文档的描述,读锁定允许每个人只读取,写锁定只允许持有者读写,而其他会话则无法访问。似乎让持有者能够读写,而其他会话仅能读取,这是一种非常经常需要的行为——可能是最常需要的行为。
也许实现这种方案的性能损失会太高?
是否可以锁定一个表,使持有者可以读写,而其他会话仅能读取?
根据文档的描述,读锁定允许每个人只读取,写锁定只允许持有者读写,而其他会话则无法访问。似乎让持有者能够读写,而其他会话仅能读取,这是一种非常经常需要的行为——可能是最常需要的行为。
也许实现这种方案的性能损失会太高?
READ
锁:WRITE
锁:让我们考虑一下什么意味着单个会话在表上保持恒定的写锁,而其他表可以按事务方式从该表读取数据。这意味着我们有一个开放的长期事务(假设为W
事务),它锁定了修改表并且其他事务(在其他会话中)可以读取已经修改但尚未提交的数据。就隔离级别而言,这意味着我们应该将默认隔离级别设置为READ-UNCOMMITTED
,这样我们就不必为每个新会话更改隔离级别:
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
但是我们的事务 W
,应该使用更强的隔离级别,否则我们无法对表应用任何锁定。 READ-COMMITTED
不够强,但是 REPEATABLE-READ
正是我们想要的。也就是在开始一个 W
事务之前,我们应该为当前会话设置事务级别:
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
CREATE TABLE t (
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
val VARCHAR(45) NOT NULL,
PRIMARY KEY (id)
) ENGINE = InnoDB;
LOCK IN SHARE MODE 不是我们想要的:
如果这些行中的任何一行被另一个尚未提交的事务更改,则您的查询将等待该事务结束,然后使用最新值。
LOCK FOR UPDATE 似乎符合我们的需求:
SELECT ... FOR UPDATE 锁定行和任何相关联的索引条目。
现在我们所需要的就是锁定行。我们可以做的最简单的事情就是锁定主键。 COUNT(*)
对于 InnoDB 来说会进行完整的索引扫描(因为 InnoDB 不知道确切的行数)。
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT COUNT(*) FROM t FOR UPDATE;
INSERT INTO t VALUES (NULL, '');
COMMIT AND CHAIN; SELECT COUNT(*) FROM ti FOR UPDATE;
begin transaction; select * from table lock in share mode
即可。但最好还是直接使用 lock table
。http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html - Byron WhitlockLOCK TABLES <table> as read_lock READ
。文档对此非常清楚。 - Byron Whitlock有SELECT ... FOR UPDATE
,它将锁定行以防止其他调用者执行SELECT ... FOR UPDATE
,但不会对执行SELECT
的任何人进行锁定。 UPDATE
将等待锁定。
当您想获取一个值并在没有任何人更改该值且您未注意到的情况下推送更新时,这非常有用。请注意,添加太多此类操作将使您陷入死锁。
你可能会发现InnoDB引擎默认情况下可以满足你的需求:写操作不会阻塞读操作。但是你需要注意事务隔离级别,以便在需要时可用写操作。