首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >MySQL :我能用一个选择吗.更新为“保护”多个表?(锁)

MySQL :我能用一个选择吗.更新为“保护”多个表?(锁)
EN

Stack Overflow用户
提问于 2016-07-23 09:43:20
回答 1查看 2.6K关注 0票数 2

我读了几个小时的MySQL文档,但我仍然不能回答自己几个非常简单的问题.:(

下面是我的(简化)场景:数据库中有两个表:tableatableb,两个表都使用InnoDB存储引擎。tablea (它是我的主表)有一个带有自动增量的主索引(id)。下面是我想要实现的目标,请记住,以下业务逻辑可以并将同时运行:

我启动了一个事务:START TRANSACTION BEGIN,然后我检查tablea中是否存在id,如果是,我选择要更新的行,让我们调用我要查找的id:SELECT `id` FROM `tablea` WHERE `id`='myid' FOR UPDATE;,如果上面的SELECT没有返回任何行,我只是回滚事务并退出我的函数。换句话说,当我的I不在tablea中时,我就完成了。另一方面,当myid存在时,首先我需要更新tableaUPDATE `tablea` SET `somefield`='somevalue' WHERE `id`='myid';中的一些值,然后我需要检查myid是否也存在于tablebSELECT * FROM `tableb` WHERE `id`='myid' FOR UPDATE;中,我的第一个问题是关于上面的SELECT语句:在这里为更新做另一个选择可以吗(在tableb上)?或者在这里处理tableb时不需要"FOR UPDATE“,因为我已经启动了一个事务,并且还根据tablea ??中的一个行获得了一个锁。有人能回答这个问题吗?

上面的最后一个SELECT语句要么从tableb返回一行(并锁定该行以进行更新),要么证明tableb中不存在myid。当myid出现在tableb中时,我只需要更新该行中的一些值,这很简单:另一方面,当UPDATE `tableb` SET `somefieldintableb`='somevaluefortableb' WHERE `id`='myid';不在tableb时,我需要插入它,下面是我的第二个问题:在发出insert INSERT语句之前,是否应该锁定tableb,比如:LOCK TABLES `tableb` WRITE; INSERT INTO `tableb` (`id`,`somefieldintableb`) VALUES ('myid','somevaluefortableb'); UNLOCK TABLES `tableb`;,最后,我需要:COMMIT

我的目标是:由于上面描述的函数(与MySQL事务一起)将在许多实例中并行运行,所以我希望防止任何这些实例同时更新tableatableb中的同一行。我还想防止在tableb中双重插入myid,因此我考虑在tableb中找不到myid时使用锁表。

所以我有两个问题:我应该做一个选择.对于我已经启动的事务中的更新,当我想更新tableb或使用SELECT锁定tableb .因为没有必要进行更新,因为保持tablea上的锁也可以“保护”tableb免受同步更新的影响--在这种情况下?我是说,多亏了我开始交易的方式。

第二个问题:当我需要在tableb中插入一个新行时,是否应该锁定整个表以进行插入?还是在这种情况下完全没有必要?(我是否需要锁表tableb?)

如果专家能帮我回答这两个问题,我将不胜感激,因为在线阅读各种文档和例子对我回答这些问题毫无帮助。:(

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-07-23 10:54:24

我会这样做:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
BEGIN;

SELECT a.`id` AS a_id, b.`id` AS b_id 
FROM `tablea` AS a LEFT OUTER JOIN `tableb` AS b ON a.id=b.id
WHERE a`id`='myid' 
FOR UPDATE;

现在,如果存在行,则表A和tableb上都有行锁。如果SELECT不返回任何内容,则您知道该id不在表A中。如果SELECT返回值为a_id的行,但返回b_id的NULL,则您知道它存在于表A中,而不是在表表中。

如果两个表中都存在行,则这将同时锁定两个表中的行。如果分两步执行,则可能会面临竞争条件和死锁的风险。

尝试插入并使用重复的键更新:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
INSERT INTO `tableb` (id, somefieldintableb) VALUES ('myid', 'somevaluefortableb') 
ON DUPLICATE KEY UPDATE `somefieldintableb`='somevaluefortableb';

如果不存在具有所需id值的行,则将插入它。如果存在行,则将更新该行。而且您肯定可以访问现有的行,因为您选择的UPDATE已经锁定了它。

如果你能避免的话,不要使用表锁。这是在应用程序中创建瓶颈的可靠方法。

关于你的评论:

是的,您可以对date列使用额外的联接条件。

在使用重复键更新时,不必更新所有列。如果存在行,则可以将它们中的大多数单独处理,只需更新一个或几个行或其他任何内容。

此外,还可以引用尝试插入的值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
INSERT INTO `tableb` (id, date, col1, col2, col3, col4, col5, col6) 
  VALUES ('myid', $a_date, ?, ?, ?, ?, ?, ?) 
ON DUPLICATE KEY UPDATE col4=VALUES(col4);

有关更多细节,我建议您阅读http://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38544770

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文