Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql读取锁定选择更新_Mysql_Node.js - Fatal编程技术网

Mysql读取锁定选择更新

Mysql读取锁定选择更新,mysql,node.js,Mysql,Node.js,编辑 我使用并拥有一个mysql连接池 原创 我有一个mysql数据库,其中有两个表: “对话”,存储元数据:用户ID(2)、主题、时间戳等 “messages”,存储具有带有conversation.id的FK的邮件 现在我总是这样: 选择一个“对话” 检查元数据是否允许请求的操作 对“对话”执行更新(更改一些元数据,例如lastUpdatedTimestamp) 可能在“消息”中插入一条消息 在消息旁边,用户还可以阻止对话(从他这边!) 会话UPDATE和可能的消息INSERT将发生在事务内

编辑

我使用并拥有一个mysql连接池

原创

我有一个mysql数据库,其中有两个表:

  • “对话”,存储元数据:用户ID(2)、主题、时间戳等
  • “messages”,存储具有带有conversation.id的FK的邮件
  • 现在我总是这样:

  • 选择一个“对话”
  • 检查元数据是否允许请求的操作
  • 对“对话”执行更新(更改一些元数据,例如lastUpdatedTimestamp)
  • 可能
    在“消息”中插入一条消息
    在消息旁边,用户还可以
    阻止
    对话(从他这边!)

    会话
    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) )