我遇到了一些奇怪的防御代码。基本上它执行这样的查询:
select * from A join B on (A.b_id=B.id)
然后它会迭代结果集,每当遇到表 B
中的新行时,它都会将其缓存(通过 id)。之后,即使对于后续行,也仅使用缓存的副本。
看起来它试图防止出现这样的结果集:
A.id | A.value | B.id | B.value
------+---------+------+---------
1 | First | 1 | Yay
2 | Second | 1 | Nay
但这可能吗?即使在 select
查询半途获取时表 B
中的行被更新,它真的会可见吗?当有人查询表时更新还能继续吗?
就其值(value)而言,我认为当时的表是 MyISAM,尽管后来它已转换为 InnoDB。此外,运行查询的代码是用 PHP 编写的。据我所知,它使用默认的事务隔离级别和获取模式。
好吧,看来我需要一些澄清。这是一段代码,与我发现的类似:
$sql = "select A.id a_id, A.value a_value, B.id b_id, B.value b_value from A join B on (A.b_id=B.id)";
$res = mysql_query($sql);
$cacheB = array();
$A = new classA();
$B = new classB();
while ($row = mysql_fetch_assoc($res)) {
$A->setData($row);
if ( !isset($cacheB[$row['b_id']]) ) {
$cacheB[$row['b_id']] = $row;
}
$B->setData($cacheB[$row['b_id']]);
// Do some processing depending on $A and $B
}
此代码是从 cron 作业运行的 CLI 应用程序。 $A
和 $B
中的数据不会返回任何内容,但根据内容,可能会调用一些外部服务,并且可能会修改一些其他数据库表。 classA
、classB
的内容及处理与本题无关。
我的问题是——这个“保障”有没有意义,或者是一个可以删除的负担?我们假设处理部分实际上对 B
值的变化敏感(尽管实际上我对此表示怀疑,但仍然如此)。
最佳答案
Can a field change during the execution of a MySQL query and both values be present in the result set?
没有。
- 在 MyISAM 中,每个查询都会锁定整个表,因此设计上根本不可能(请参阅 table locking)。
- 在 InnoDB 中,查询是隔离的,选择是一致的读取,如文档 Locks Set by Different SQL Statements in InnoDB 中所述。 。 一致性读取被定义为“使用快照信息基于某个时间点呈现查询结果的读取操作,而不管同时运行的其他事务执行的更改如何。” em>”
Even if the row in table B is updated while the select query is fetched half way, will it really be visible?
是的,即便如此,这也是不可能的。
Can the update even proceed while someone is querying the table?
在 MyISAM 中,不,它必须等待,正如文档中所解释的:“表锁定使许多 session 能够同时从表中读取,但是如果一个 session 想要写入表,它必须首先获得独占访问权限,这意味着它可能必须等待其他 session 首先完成该表。在更新期间,所有其他想要访问此特定表的 session 必须等待更新完成。"
在 InnoDB 中是的,但是查询是隔离的,并且按照解释在数据库的不同“快照”上工作,所以这并不重要。如果您有任何疑问,交易在这种情况下特别有用。
您显示的代码可能有也可能没有其他目的,这一点我不能说。但如果它的唯一目的是防止不可能发生的事情发生,那么它就完全多余了,可以安全地删除。
关于php - 执行 MySQL 查询期间字段是否可以更改并且两个值都出现在结果集中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48226707/