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