【发布时间】:2016-07-23 17:43:20
【问题描述】:
我正在阅读 MySQL 文档几个小时,但我仍然无法回答自己几个非常简单的问题... :(
这是我的(简化的)场景:我在数据库中有两个表:tablea 和 tableb,这两个表都使用 InnoDB 存储引擎。 tablea(这是我的主表)有一个带自动增量的主索引 (id)。现在这是我想要实现的目标,请记住,以下业务逻辑可以并且将会同时运行:
我开始交易:
START TRANSACTION
BEGIN
然后我检查tablea 中是否存在 id 如果是,我选择更新行,让我们调用我正在寻找的 id myid :
SELECT `id` FROM `tablea` WHERE `id`='myid' FOR UPDATE;
如果上面的 SELECT 没有返回任何行,我只需 ROLLBACK 事务并退出我的函数。换句话说,当 tablea 中不存在 myid 时,我就完成了。
另一方面,当 myid 存在时,首先我需要更新tablea 中的一些值:
UPDATE `tablea` SET `somefield`='somevalue' WHERE `id`='myid';
那么我需要检查tableb中是否也存在myid:
SELECT * FROM `tableb` WHERE `id`='myid' FOR UPDATE;
我的第一个问题是关于上面的 SELECT 语句:可以在这里做另一个 SELECT FOR UPDATE 吗(在tableb)?或者在处理tableb 时这里不需要“FOR UPDATE”,因为我已经开始了一个事务并且还获得了一个基于tablea 中的行的锁???有人可以回答这个吗?
上面的最后一个 SELECT 语句要么从 tableb 返回一行(并锁定该行以进行更新),要么证明 myid 在 tableb 中不存在。
当tableb 中存在 myid 时,我只需要更新该行中的一些值,这很简单:
UPDATE `tableb` SET `somefieldintableb`='somevaluefortableb' WHERE `id`='myid';
另一方面,当 myid 不在tableb 中时,我需要插入它,这是我的第二个问题:我是否应该在发出 INSERT INTO 语句之前锁定tableb,如下所示:
LOCK TABLES `tableb` WRITE;
INSERT INTO `tableb` (`id`,`somefieldintableb`) VALUES ('myid','somevaluefortableb');
UNLOCK TABLES `tableb`;
最后,我这样做:
COMMIT
我的目标是:由于上述函数(使用 MySQL 事务)将在许多实例中并行运行,我想防止任何这些实例更新 tablea 或 tableb 中的同一行同时。我还想防止 myid 重复插入tableb,因此我考虑在tableb 中找不到 myid 时使用 LOCK TABLES。
所以我有两个问题:当我想要更新 tableb 或锁定 tableb 时,我应该在我已经开始的事务中执行 SELECT ... FOR UPDATE 是不必要的,因为持有在这种情况下,锁定tablea 已经“保护”tableb 免受同时更新???感谢我开始交易的方式。
第二个问题:当我需要在tableb 中插入新行时,我应该锁定整个表以进行该插入吗?还是在这种情况下完全没有必要这样做? (我需要 LOCK TABLES tableb 吗?)
如果专家可以为我回答这两个问题,我将不胜感激,因为在线阅读各种文档和示例并不能帮助我回答这些问题。 :(
【问题讨论】:
标签: mysql select transactions locking innodb