MySQL表锁定:持有者读写,其他会话只读?
是否可以锁定一个表,使得持有者可以读写,而其他会话只能读?
文档似乎建议读锁允许每个人只读,写锁只允许持有者读写,其他会话无权访问。似乎让持有者能够读取和写入而其他会话只能读取将是一种非常频繁需要的行为——也许是最频繁需要的行为。
也许实施这种方案对性能的影响会太大?
Is it possible to lock a table such that the holder can read and write, and other sessions can only read?
The documentation seems to suggestion that a read lock allows everyone to only read, and a write lock allows only the holder to read and write and other sessions have no access. Seems like having the holder able to read and write and other sessions only able to read would be a pretty frequently needed behavior -- perhaps the most frequently needed behavior.
Maybe the performance hit in implementing this scenario would be too high?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
看看锁定共享模式 。
这将允许您设置非阻塞读锁。
但请记住,这可能会导致僵局!确保您可以接受包含过时信息的流程。
Take a look at LOCK IN SHARE MODE.
This will let you set non blocking read locks.
But remember, this can lead to deadlocks! Make sure you are okay with processes having out of date information.
现有答案中有很多正确的话,但似乎没有人给出明确的答案。我会尝试。
正如您在锁定表的文档中已经看到的那样,它不能用于此目的,因为对于 READ 锁:
对于
WRITE
锁:就是这个效果用任意引擎表很难达到,但是用事务型引擎,也就是InnoDB就可以达到。
我们想一下,什么意思是单个会话对一个表保持恒定的写锁,而其他表可以从事务的角度读取该表的数据。这意味着我们有一个开放的长期事务(让它成为
W
事务),它锁定表以进行修改,并且其他事务(在其他会话中)可以读取已修改但尚未提交的数据。就隔离级别而言,这意味着我们应该将默认隔离级别设置为 READ-UNCOMMITTED,这样我们就不必为每个新会话更改隔离级别:但是我们的事务
W
,应该使用更强的隔离级别,否则我们无法对表应用任何锁定。READ-COMMITTED
不够强大,但REPEATABLE-READ
正是我们想要的。也就是说,在启动W
事务之前,我们应该为当前会话设置事务级别:现在,如何锁定整个表。让我们创建一个表:
锁定共享模式不是我们想要的:
锁定更新似乎可以满足我们的需要:
现在我们需要的就是锁定行。我们能做的最简单的事情就是锁定主键。
COUNT(*)
对 InnoDB 进行完整索引扫描(因为 InnoDB 不知道确切的行数)。现在您可以打开其他会话并尝试从表中读取数据并尝试添加或修改这些会话中的现有数据。
但问题是,您应该在
W
中提交修改,并且一旦您提交事务,锁就会被释放,并且所有等待的插入或更新也会被应用,即使您提交了它with:这个故事的寓意是,拥有两个 MySQL 帐户要容易得多:a) 具有 INSERT、UPDATE 和 DELETE 的写入帐户 授予权限,以及 b) 读取尚未授予权限的帐户。
There are many correct words in existing answers, but no one seems to have given a clear answer. I will try.
As you have already seen in documentation on LOCK TABLES, it can not be used for the purpose, since for the
READ
lock:and for the
WRITE
lock:That is the effect can hardly be achievable with an arbitrary engine table, but it can be achived with a transactional engine, that is InnoDB.
Let's think about what means that a single session keeps a constant write lock on a table and other tables can read data from the table in terms of transactions. That means that we have an open long living transaction (let it be
W
transaction) which locks a table for modifications and other transactions (in other sessions) can read data that is already modified, but not yet committed. In terms of isolation levels, that means that we should set up the default isolation level toREAD-UNCOMMITTED
, so that we would not have to change the isolation level for each new session:But our transaction
W
, should use a stronger isolation level, otherwise we can not apply any locking to our table.READ-COMMITTED
is not strong enough, butREPEATABLE-READ
is exactly what we want. That is befor starting aW
transaction we should set the transaction level for the current session:Now, how to lock the whole table. Let's create a table:
LOCK IN SHARE MODE is not what we want:
LOCK FOR UPDATE seems to do what we need:
Now all we need is to lock the rows. The simplest thing we can to is to lock the primary key.
COUNT(*)
does a full index scan for InnoDB (since InnoDB does not know that exact row count).Now you can open other sessions and try to read the data from the table and try to add or modify the existing data from those sessions.
The problem is though, that you should commit the modifications in
W
, and as soon as you commit the transaction, the lock is released and all waiting inserts or updates are applied as well, even if you commit it with:The moral of the story is that it is much easier to have two MySQL accounts: a) writing account which has INSERT, UPDATE and DELETE GRANT permissions, and b) reading account which has not.
有
选择...进行更新
,这将为执行
SELECT ... FOR UPDATE
的其他调用者锁定行,但不会为仅执行SELECT
的任何人锁定行。UPDATE
s 也会等待锁。当您想要获取一个值然后推送更新而没有人更改该值并且您没有注意到时,这非常有用。小心,添加太多会让你陷入僵局。
There is
SELECT ... FOR UPDATE
, which will lock the rows for other callers that doSELECT ... FOR UPDATE
, but will not lock it for anyone doing justSELECT
.UPDATE
s will wait for the lock, as well.This is useful when you want to fetch a value and then push an update back without anyone changing the value and you not noticing. Be careful, adding too much of those will get you into a deadlock.
您可能会发现 InnoDB 引擎默认执行您需要的操作:写入不会阻止读取。您需要小心事务隔离级别,以便在需要时可以进行写入。
You may find that the InnoDB engine does what you need by default: writes do not block reads. You need to be careful with the transaction isolation level so that writes are available when you want them.