首先是一点点背景: 我正在写一个浏览器游戏,练习我的网络技能和乐趣:)有些用户拥有一些工厂和一个主要的仓库。它们产生不同类型的产品,这些产品存储在内部工厂中。用户可以“聚集”工厂,将成品转移到他们的主仓库。
为了实现,我使用PHP和PDO作为数据库连接器。我的网络服务器使用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”返回错误。虽然调试在我看来,交易不等待另一个完成,但我不确定这个。
现在我的问题:
答案 0 :(得分:1)
该错误告诉您在已经出错的事务中发出语句。虽然早先的陈述似乎没有失败,但他们可能会这样做; PDO和PHP没有注意到强大而仔细的错误处理。
我强烈建议您在运行测试时检查PostgreSQL日志文件。看看失败的地方和地点。设置log_line_prefix
可能会有所帮助,这样您就可以通过显示后端进程ID更轻松地查看哪些语句来自哪些会话,例如:
log_line_prefix = 'ss=%e pid=%p cmd=%i'
您可能还想设置log_statement = all
。
您很可能会看到PDO发出的查询产生错误,因此您的下一个语句会尝试在中止的事务中执行并生成25P02 in_failed_sql_transaction
。
SERIALIZABLE
隔离才能获得一致结果的用例。您是否考虑过只使用UNION ALL
和SELECT
两个?{/ p>
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;