Mysql读取锁定选择更新
编辑 我使用并拥有一个mysql连接池 原创 我有一个mysql数据库,其中有两个表:Mysql读取锁定选择更新,mysql,node.js,Mysql,Node.js,编辑 我使用并拥有一个mysql连接池 原创 我有一个mysql数据库,其中有两个表: “对话”,存储元数据:用户ID(2)、主题、时间戳等 “messages”,存储具有带有conversation.id的FK的邮件 现在我总是这样: 选择一个“对话” 检查元数据是否允许请求的操作 对“对话”执行更新(更改一些元数据,例如lastUpdatedTimestamp) 可能在“消息”中插入一条消息 在消息旁边,用户还可以阻止对话(从他这边!) 会话UPDATE和可能的消息INSERT将发生在事务内
选择一个“对话”
在“消息”中插入一条消息李>
在消息旁边,用户还可以阻止
对话(从他这边!)
会话UPDATE
和可能的消息INSERT
将发生在事务内部
一个警告:在我选择
对话行并在应用程序级别检查元数据后,可能是不允许请求的操作,导致更新
和可能的插入
永远不会执行
Q1
现在,如何从我选择对话行的那一刻开始读取它?但当元数据导致“用户错误”(例如,当前用户ID不是“此”对话中的用户ID)时,仍然能够释放锁
Q2
现在我正在使用一个redis“locks”db,它通过使用Lua锁定一个给定的id,并使用node.js事件来释放这个锁。这些redis锁有一个超时。(例如,1000毫秒)。有没有办法设置mysql锁的超时时间?您正在寻找命名锁(小心,危险的东西,不要在生产服务器上尝试锁:D)
看看:
A1:选择要锁定的唯一字符串,并在其上使用GET_lock
(例如,GET_lock('conversation| |[id])
;如果返回1
,则锁定属于您。执行任何您想要的操作,然后调用RELEASE_lock
(考虑所有可能的情况,包括错误)
A2:获取锁定
的第二个参数是秒内的超时。如果操作超时,获取锁定
将返回0
从官方文件
获取锁(str,超时)
尝试使用
超时时间timeout
秒。如果获得锁,则返回1
成功,0
如果尝试超时(例如,因为另一个
客户端以前已锁定名称),如果发生错误,则为NULL
(例如内存不足或线程被终止)
mysqladmin kill)。如果您有一个通过GET_lock()
获得的锁,则它是
执行RELEASE_LOCK()
,执行新的GET_LOCK()
1时释放,或
连接终止(正常或异常)2。锁定
使用GET\u LOCK()获取。
不与事务交互。即,
提交事务不会释放获得的任何此类锁
在交易期间
此功能可用于实现应用程序锁定或
模拟记录锁定。名称在服务器范围内的basis3上锁定
名称已被一个客户端锁定,GET\u LOCK()
通过
为具有相同名称的锁创建另一个客户端。这将启用客户端
同意使用给定的锁名称来执行协作
建议锁定。但请注意,它还支持
也不是在一组合作客户机中锁定名称
无意或故意,从而阻止任何合作
阻止客户端锁定该名称。一种降低
这是为了使用特定于数据库或
特定于应用程序。例如,使用窗体的锁名称
db\u name.str
或app\u name.str
粗体字是我的:
意味着您每个连接只能持有一个锁(对于您的用户案例来说不是问题)
表示一旦关闭连接,锁将被释放
意味着两个不同的连接(即使来自同一个池)可能无法同时获得相同的外观
目前还不完全清楚您想要实现什么。但就我所知,没有任何本机MySQL“锁定”机制可以满足您的需要(您希望一个会话能够“锁定”一行,以防止另一个会话“读取”(或修改)该行)
要完成您试图完成的任务,这听起来像是应用程序问题,而不是数据库完整性问题
我将使用的解决方法是向表中添加两列:
locked_by - uniquely identify the session holding the row lock
locked_at - the date/time the row lock was placed
对于试图获得对行的锁定的会话,我将检查该行是否已被其他会话锁定,如果未被锁定,则将该行标记为已被该会话锁定:
UPDATE mytable
SET locked_by = 'me'
, locked_at = NOW()
WHERE unique_row_identifer = someval
AND locked_by IS NULL;
如果更新返回的是“零行更新”,那么您就知道没有获得锁。
如果返回值不为零,则表示您已获得锁(至少在一行上)
要检查我的会话是否已持有该行的锁,请执行以下操作:
SELECT 1
FROM mytable t
WHERE t.unique_row_identifier = someval
AND locked_by = 'me';
一旦我知道行上有一个“锁”,我就可以通过简单的选择来检索它
SELECT ... WHERE unique_row_identifier = someval`
要释放锁,会话将
的locked_和
列的locked_设置回NULL
“只读”会话可以通过检查locked_by列中的值来避免读取锁定的行:
SELECT t.*
FROM mytable t
WHERE t.unique_row_identifier = someval
AND t.locked_by IS NULL
该行只有在未锁定时才会返回
请注意,我会在一条语句中执行锁定和检查,以避免同时出现竞争情况
WHERE ( locked_at IS NULL OR locked_at < (NOW() + INTERVAL 24 HOUR) )