【问题标题】:How to write lock table while inserting data in MySQLMySQL插入数据时如何写锁表
【发布时间】:2018-12-11 06:50:38
【问题描述】:

目标

当用户发出请求(REST API)时,我想将 N 记录从表 source 复制到表 destination

当前解决方案

  1. 开始事务。
  2. 截断表destination
  3. 插入表destination select from source LIMIT N(单个查询)。
  4. 提交事务。

问题

N 可以介于100000 - 2500000 之间,如果用户使用N 记录一个接一个地发出两个请求,则将插入2xN 记录。

示例流程:

  1. [Action - 1] 用户请求复制 100 记录。
  2. [Action - 1] 交易开始。
  3. [Action - 2] 用户请求复制 200 记录。
  4. [Action - 1] 截断表destination
  5. [Action - 2] 交易开始。
  6. [Action - 2] 截断表destination
  7. [操作 - 1] 插入查询已触发。(复制 100 记录)
  8. [操作 - 2] 插入查询已触发。(复制 200 记录)
  9. [Action - 1] 交易结束。
  10. [Action - 2] 交易结束。

结果:destination 表中有300 记录。

所需的解决方案

我想确保在任何给定时间点只发生一次插入。

  1. 开始交易。
  2. 锁定destination 表。
  3. 截断destination 表。
  4. 插入destination 表。
  5. 解锁destination 表。
  6. 结束交易。

请注意,当我只想写入锁定目标表时,不应发生 写入 操作(但仍应发生读取操作)。

其他详情

  • MySQL(数据库)
  • NodeJS(REST API 服务器)
  • 没有存储过程

临时解决方案

暂时我们依赖于在开始事务之前在数据库中设置的标志,然后在事务完成后取消设置。设置标志时到达的任何其他请求都将终止并显示一条消息(进程已在运行,请稍后再试)

请帮助我找到更好的解决方案。如果您需要更多详细信息,请告诉我。

谢谢

【问题讨论】:

  • MySQL 可以挂起请求并在表被锁定时一一执行。如果你害怕超时。只需将connect_timeout 设置为您想要的足够长的时间。
  • 也许更好地解释您要解决的问题,而不是您想如何解决它,这会带来一些更好的方法,这个方法很糟糕。在我看来XYProblem
  • @JorgeCampos 是的,我已经提到了我的问题。我不希望 2 次插入同时发生。
  • @MatrixTai 您能否详细说明或指出一些参考资料?
  • mysqltutorial.org/mysql-table-locking,看看,你可以一个一个的执行请求。

标签: mysql node.js mariadb


【解决方案1】:

你能退一步解释一下目标是什么吗?同时,这里有另一个可能有帮助的实现:

CREATE TABLE new LIKE dest;
populate `new` from `source;
RENAME TABLE dest TO old, new TO dest;
DROP TABLE old;

注意事项:

  • 除了每个语句都是原子的之外,没有锁或事务。
  • 填充dest 可能需要任意长的时间,而不会出现任何锁定问题。
  • dest 始终可用,除了RENAME 期间的短暂时间,在此期间dest 上的活动被阻止。

这是一种以原子方式重新加载表的通用方法,影响最小。

【讨论】:

    【解决方案2】:

    您可以尝试以下查询...

    SET AUTOCOMMIT=0;
    LOCK TABLES `staff` WRITE;
    
    -- inserts start here
    INSERT INTO `staff` VALUES 
    (2,'Jon','Snow',4,NULL,'Jon.snow@gameofthroneshbo.com',2,1,'Jon',NULL,'2006-02-15 03:57:16'),
    (2,'Jon','Stephens',4,NULL,'Jon.Stephens@sakilastaff.com',2,1,'Jon',NULL,'2006-02-15 03:57:16');
    -- till here
    
    UNLOCK TABLES;
    COMMIT;
    

    【讨论】:

    • 嗨@Saurabh Ande 请注意,虽然 WRITE 锁会锁定新的 SELECT 查询,直到它转换为 READ 锁或通过 UNLOCK 释放,但它不会阻止查询缓存中已经存在的 SELECT 查询返回缓存的结果。所以我可以在staff 上使用选择查询,直到我解锁它。
    【解决方案3】:

    您如何优化您的 SQL 查询以在插入记录时执行 Lock-Unlock 场景:

    LOCK TABLES
        tbl_name [[AS] alias] lock_type
        [, tbl_name [[AS] alias] lock_type] ...
    
    lock_type:
        READ [LOCAL]
      | [LOW_PRIORITY] WRITE
    
    UNLOCK TABLES
    

    更多信息 - https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-12
      • 1970-01-01
      • 1970-01-01
      • 2015-01-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多