在MySQL中插入数据时如何写锁表

时间:2018-07-03 03:47:08

标签: mysql node.js mariadb

客观

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

当前解决方案

  1. 开始交易。
  2. 截断表destination
  3. 插入表destination中,从source LIMIT N中进行选择(单个查询)。
  4. 提交交易。

问题

N可以在100000-2500000范围之间,如果用户使用N记录一个接一个地发出两个请求,则2xN个记录是被插入。

示例流程:

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

结果:300表中有destination条记录。

所需解决方案

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

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

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

其他详细信息

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

临时解决方案

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

请帮助我为此找到更好的解决方案。让我知道您是否需要更多详细信息。

谢谢

3 个答案:

答案 0 :(得分:0)

您能退后一步,解释一下目标是什么吗?同时,这是另一个可能有用的实现:

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

注意:

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

这是一种原子化的通用方法,并且在影响最小的情况下重新加载表。

答案 1 :(得分:0)

您可以尝试以下查询,如下所示...

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;

答案 2 :(得分:0)

如何优化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