1

首先是一点背景:我正在编写一个小浏览器游戏来练习我的网络技能和乐趣:) 有些用户拥有一些工厂和一个主仓库。这些生产不同类型的产品,这些产品存储在内部工厂仓库中。用户可以“聚集”工厂,将成品转移到他们的主仓库。

为了实现,我使用带有 PDO 的 PHP 作为数据库连接器。我的网络服务器使用 MySQL 数据库,我使用本地 Postgres 数据库进行调试。

用户应该能够在不点击收集链接的情况下收集所有工厂并等待响应。因此,我使用 Ajax,以便用户可以单击所有工厂一次并等待所有请求完成。为了防止这种并行访问在我的数据库中引入不一致,我使用隔离级别 SERIALIZABLE 的事务。因为 pdo 不支持隔离级别,所以我在与我的 Postgres-db 的连接处发送一个查询

SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET statement_timeout=10000;

第二个查询应该防止并行事务取消,而另一个事务正在进行中。两个查询都没有返回错误,但不起作用。当我发送 8 个几乎并行的请求时,其中只有 2-3 个成功返回,另一个从 postgres “25P02 IN FAILED SQL TRANSACTION”返回错误。在我看来,在调试时,事务不会等待另一个完成,但我不确定这一点。

现在我的问题:

  1. 是否有可能使用 PDO 获得隔离级别和超时?
  2. 有没有我可以使用的替代品?(除了 Zend 这样的重量级框架,我想深入探索所有机制)
  3. 如果我只使用一种类型的数据库和像 mysqli 这样的专用连接器,我可以解决我的问题吗?我认为使用 PDO 更灵活是个好主意,但可能对浏览器游戏不利。
  4. 我的数据库访问方法可以吗?还是有更好的设计?
  5. 这样的错误是否正常,这样的交易是否应该循环直到成功?如果是,在客户端使用 Ajax 还是在服务器端使用 PHP?
4

1 回答 1

1

该错误告诉您,您在已经出错的事务中发出语句。虽然早期的陈述似乎没有失败,但他们可能已经失败了;PDO 和 PHP 没有以健壮和谨慎的错误处理而著称。

我强烈建议您在运行测试时检查 PostgreSQL 日志文件。看看失败的地方和地方。设置 a 可能会有所帮助,log_line_prefix这样您就可以通过显示后端进程 ID 更轻松地查看哪些语句来自哪些会话,例如:

log_line_prefix = 'ss=%e pid=%p cmd=%i'

您可能还想设置log_statement = all.

您很可能会看到 PDO 发出的查询会产生错误,因此您的下一条语句会尝试在中止的事务中执行并产生25P02 in_failed_sql_transaction.


顺便说一句,这似乎不是一个特别需要SERIALIZABLE隔离才能获得一致结果的用例。您是否考虑过仅将 aUNION ALL与您的两个SELECTs 一起使用?

SELECT 'internal', count(inventory_items) FROM internal_inventory
UNION ALL
SELECT 'main', count(inventory_items) FROM main_inventory;

或者如果架构更好:

SELECT isinternal, count(inventory_items)
FROM inventory
GROUP BY isinternal;
于 2012-10-20T02:07:08.777 回答