我正在阅读MySQL文档数小时,但仍然无法回答几个非常简单的问题... :(
这是我的(简化)方案:数据库中有两个表:tablea
和tableb
,两个表都使用InnoDB存储引擎。tablea
(这是我的主表)具有id
带有自动增量的PRIMARY索引()。现在,这是我要实现的目标,请记住,以下业务逻辑可以并且将同时运行:
我开始一个事务: START TRANSACTION BEGIN
然后检查是否存在id,tablea
如果是,我选择行FOR UPDATE,让我们将其称为id,我正在寻找myid: SELECT `id` FROM `tablea` WHERE `id`='myid' FOR UPDATE;
如果上面的SELECT不返回任何行,我只是回滚事务并退出我的交易功能。换句话说,当myid不存在时,我就完成了tablea
。另一方面,当myid存在时,我首先需要更新中的一些值tablea
: UPDATE `tablea` SET `somefield`='somevalue' WHERE `id`='myid';
然后我需要检查myid中是否还存在tableb
: SELECT * FROM `tableb` WHERE `id`='myid' FOR UPDATE;
我的第一个问题是关于上述SELECT语句的:是否可以在此处进行另一个SELECT FOR UPDATE?tableb
)??? 或在进行处理时tableb
,此处不需要“ FOR UPDATE” ,因为我已经启动了事务并且还基于tablea
???中的行获取了一个锁?有人可以回答吗?
上面的最后一个SELECT语句返回一个行tableb
(并锁定该行以进行更新),或者事实证明myid在中不存在tableb
。当myid存在时,tableb
我只需要更新该行中的一些值,这很简单: UPDATE `tableb` SET `somefieldintableb`='somevaluefortableb' WHERE `id`='myid';
另一方面,当myid不存在时,tableb
我需要插入它,这是我的第二个问题:tableb
在发出INSERT之前应该锁定吗?像这样的INTO语句: LOCK TABLES `tableb` WRITE; INSERT INTO `tableb` (`id`,`somefieldintableb`) VALUES ('myid','somevaluefortableb'); UNLOCK TABLES `tableb`;
然后最后,我这样做: COMMIT
我的目标是:由于上述函数(带有MySQL事务)将在许多实例中并行运行,因此我想防止这些实例中的任何一个在同一时间tablea
或tableb
同一时间更新同一行。我还想防止将myid双重插入tableb
,因此我考虑了在中找不到myid时使用LOCK TABLES tableb
。
所以我有两个问题:当我想用SELECT ... FOR UPDATE进行更新tableb
或锁定时tableb
,是否应该在已启动的事务中执行SELECT ... FOR UPDATE,这是不必要的,因为也要同时锁定tablea
已经“保护”的锁tableb
在这种情况下的更新???多亏了我开始交易的方式,我的意思是。
第二个问题:当我需要在其中插入新行时,tableb
是否应该锁定整个表以进行插入?还是在这种情况下完全不需要的东西?(我是否需要锁定表tableb
?)
如果专家可以为我回答这两个问题,我将不胜感激,因为在线阅读各种文档和示例将完全无法帮助我回答这些问题。:(
我会这样:
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和表B行锁,如果存在的行。如果SELECT不返回任何内容,则说明ID在表中不存在。如果SELECT返回的行的a_id值为,但b_id的值为NULL,则您知道它存在于tablea中,而不存在于tableb中。
如果在两个表中都存在该行,则这将同时锁定两个表中的行。如果分两步进行操作,则可能会面临竞争状况和死锁的风险。
尝试INSERT并使用ON DUPLICATE KEY UPDATE:
INSERT INTO `tableb` (id, somefieldintableb) VALUES ('myid', 'somevaluefortableb')
ON DUPLICATE KEY UPDATE `somefieldintableb`='somevaluefortableb';
如果不存在具有所需id值的行,则将其插入。如果存在该行,则将更新该行。而且您肯定可以访问现有行,因为您的SELECT FOR UPDATE之前已将其锁定。
如果可以避免,请不要使用表锁。这是在应用程序中创建瓶颈的肯定方法。
对您的评论:
是的,您可以在日期列中使用额外的加入条件。
使用ON DUPLICATE KEY UPDATE时不必更新所有列。如果该行存在,您可以不理会它们中的大多数,而只更新其中的一个或几个。
您也可以引用您尝试插入的值。
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
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句