MySQL - 如何检查 UPDATE rowCount = 0 的原因

MySQL - how to check reason for UPDATE rowCount = 0

我正在尝试解决数据库中的一些并发问题。我正在开发的应用程序需要能够使用 MySQL、PostgreSQL 和 SQLite。在连续执行 UPDATE 时,我检查结果行数。在两种情况下,行计数可以为 0 - a) 该行已被另一个具有相同值的请求更新,或者 b) 该行已被另一个客户端删除。在场景 a 中没有问题,但在场景 b 中请求应该失败。有没有 easy/thread-safe 的方法来区分?如果它可以 return rowCount=0 用于场景 a 并为场景 b 抛出一个实际错误,就像 INSERT INTO 如果两个客户端同时插入一个冲突的行一样.我唯一能想到的是重新查询该行是否仍然存在,但这是 1) 浪费和不雅观的,2) 仍然不是线程安全的——可以在 UPDATESELECT。我正在使用 READ COMMITTED 隔离级别,因此在请求期间可以出现新数据。

我注意到,通过命令行执行此操作时,您可以分辨出来,至少 MySQL 是这样。如果它适用于所有三个,那么也许这只是一个 PHP-PDO 问题。 PDO 只有一个 rowCount()。对于 MySQL 至少问题可以用 PDO::MYSQL_ATTR_FOUND_ROWS 解决,但这似乎不适用于 Postgres/SQLite.

MariaDB [test]> update test set id=72;
Query OK, 0 rows affected (0.000 sec)
Rows matched: 1  Changed: 0  Warnings: 0

我还发现我可以在每个 UPDATE 之后跟进一个 SELECT FOUND_ROWS() 但这似乎有点老套。如果可能的话,我宁愿避免两次查询。理想情况下,我正在寻找一种方法让它只报告匹配的行数,而不是受影响的行数。

我不确定这个解决方案是否对您有帮助:

让我们假设您有这样的 table:

并且您想管理不同客户端的并行更新和删除。所以我的建议是更改 table 结构。并使其特定于客户:

所以每个客户都可以 update/insert 基于相关数据。并创建一个仅显示 ID 和值的视图 - 它根据最新状态工作并过滤掉已删除的记录 -

视图查询可以是:

select ID, VALUE
  from (
        select ID, 
               VALUE,
               STATUS,
               ROW_NUMBER() OVER(PARTITION BY ID ORDER BY STATUS_DATE DESC) RN 
          from table m
       )dt
 where 1 = 1
   and rn = 1
   and STATUS <> 'Deleted'
  

也许这对您的工作来说不是一个好的解决方案。只是一个想法,也许它可以帮助。

事实证明,我正在寻找的行为已经是 PostgreSQL 中的默认行为。手册指出“计数是更新的行数,包括值未更改的匹配行”。

对于 MySQL,可以通过 PDO::MYSQL_ATTR_FOUND_ROWS 获得所需的行为。

对于 Sqlite,PDO 文档指出 rowCount()“returns“0”(零)始终与 SQLite 驱动程序一起使用”,但这似乎不是真的。我 运行 一个测试脚本,它似乎已经和 PostgreSQL 一样工作了。我的系统是 运行 libsqlite 3.35.5, PHP 7.4.27.

<?php

$db = new \PDO("sqlite:test.db");
$db->query("delete from test");

$result = $db->query("insert into test values(65)");
echo "insert: count: ".$result->rowCount()."\n";

$result = $db->query("update test set id=55 where id=65");
echo "update changed: count: ".$result->rowCount()."\n";

$result = $db->query("update test set id=55 where id=55");
echo "update not changed: count: ".$result->rowCount()."\n";

$result = $db->query("update test set id=55 where id=65");
echo "update not existing: count: ".$result->rowCount()."\n";

产量...

insert: count: 1
update changed: count: 1
update not changed: count: 1
update not existing: count: 0