我正在阅读MySQL文档几个小时,但我仍然无法回答自己几个很简单的问题...... :(MySQL:我可以使用一个SELECT ... FOR UPDATE来“保护”多个表吗? (LOCKING)
这是我的(简化)情况:我有两个表数据库:tablea
和tableb
,这两个表都使用InnoDB存储引擎tablea
(这是我的主表)有一个带有自动增量的主索引(id
)现在这是我想要实现的,请记住以下业务逻辑可以并将同时运行:
我开始交易: START TRANSACTION BEGIN
然后我检查一个id是否存在在tablea
如果是的话,我选择行FOR UPDATE,让我们打电话给我找我的ID: SELECT `id` FROM `tablea` WHERE `id`='myid' FOR UPDATE;
如果上面的SELECT返回没有行,我只需ROLLBACK事务并退出我的功能。换句话说,当我在tablea
中不存在myid时,我就完成了。 就当身份识别码先存在,那么我需要tablea
更新一些价值观另一方面: UPDATE `tablea` SET `somefield`='somevalue' WHERE `id`='myid';
然后我需要检查,如果身份识别码也存在于tableb
: SELECT * FROM `tableb` WHERE `id`='myid' FOR UPDATE;
我的第一个问题是关于上面的SELECT语句:这是好的在这里做另一个SELECT FOR UPDATE(在tableb
)???或“更新”是不是这里tableb
打交道时,因为我已经开始交易需要,也收购了总部设在tablea
一排锁???有人可以回答吗?
上面的最后一条SELECT语句从tableb
返回一行(并锁定该行以进行更新),或者结果显示myid在tableb
中不存在。 当身份识别码出现在tableb
那么我只需要在该行中更新一些价值观,这很简单: UPDATE `tableb` SET `somefieldintableb`='somevaluefortableb' WHERE `id`='myid';
在另一方面,当身份识别码不tableb
我需要插入它,这才是我的第二个问题:我应该锁定tableb
之前,我发出了我的INSERT INTO语句,就像这样: LOCK TABLES `tableb` WRITE; INSERT INTO `tableb` (`id`,`somefieldintableb`) VALUES ('myid','somevaluefortableb'); UNLOCK TABLES `tableb`;
,最后,我做的: COMMIT
我的目标是这样的:由于上述的功能(与MySQL的交易)会在许多情况下运行同时,我想阻止任何这些实例更新tablea
或tableb
中的同一行 与此同时。我也想防止身份识别码的双插入tableb
,所以我想过使用LOCK TABLES时tableb
没有被发现身份识别码。
所以我有两个问题:我应该做一个SELECT ... FOR我已经开始了事务中更新时,我想更新tableb
或SELECT锁定tableb
... FOR UPDATE是不必要的,因为持有tablea
锁在这种情况下已经同时更新“保护”tableb
???我的意思是,感谢我开始交易的方式。
第二个问题:当我需要插入一个新行tableb
我应该锁定整个表的插入?或者在这种情况下完全没有必要? (我是否需要锁表tableb
?)
如果专家能回答这两个问题,我会很感激,因为在线阅读各种文档和示例根本无法帮助我回答这些问题。:(
谢谢你,比尔!我有两个步骤做事的原因(我提到这只是一个简单的例子)。 tableb中的myid不是唯一的,而是在tableb中,这两个字段是唯一的(这是tableb中的PRIMARY索引,没有自动增量):'id','date'。所以在tableb中我每天只有一个(或零)ID。在这种情况下,我仍然可以使用单个SELECT FOR ... UPDATE吗?考虑一下,我可以做到这一点,但我需要为外部联接添加一个WHERE子句:AND tableb.date = DATE(NOW())您怎么看? – Zoltan
我也不想使用ON DUPLICATE KEY UPDATE,因为:当myid存在于tableb中(对于今天的日期),那么我只需要更新tableb中该行的单个字段。但是,当myid不在tableb中(今天的日期),那么我需要插入总共6个字段值,并为额外的5个字段收集这些值是我的程序中的一个昂贵的操作。所以在可能的情况下,我只想更新tableb中的一个字段,而不是全部6个字段。 (简单的例子不工作!)) – Zoltan
这工作?作为一个左外部连接'tableb'作为一个b.id = b.id和b.date = DATE(NOW())作为一个左外部连接'tableb'作为a_id, ) WHERE a'id' ='myid' ? – Zoltan