0

我有一个 PostgreSQL 9.2.2 数据库,为我的 ERP 系统提供订单。数据库表包含布尔列,指示是否在其他记录中添加了客户。我使用的代码从数据库中提取行并将它们一次发送到我们的 ERP 系统(单线程)。我的代码在这方面工作得很好;但是在过去的一年中,我们的数量已经增长到足以需要多线程解决方案。

我认为 MVCC 模式对我不起作用,因为 added_customer 列仅在成功添加客户后更新。默认的 MVCC 模式可能会导致同时处理同一行,从而导致重复的 Web 服务调用。我要避免的是对我们的 ERP 系统的重复 Web 服务调用,因为它们可能相当繁重,尽管我承认我不是 MVCC 方面的专家,也不是 PostgreSQL 提供的其他模式的专家。

我的问题是:如何确保在一个 select 语句中返回的一行或一系列行被排除在单独线程中对数据库的其他查询之外?

4

2 回答 2

0

您可以在表格中添加一列user_is_proccesed。它可以保存用于更新记录的后端进程 ID。

然后使用一个小的可序列化事务将其设置user_is_proccesed为“锁定行以进行处理”。

就像是:

START TRANSACTION  ISOLATION LEVEL SERIALIZABLE;

UPDATE user_table
SET user_is_proccesed = pg_backend_pid()
WHERE <some condition>
  AND user_is_proccesed IS NULL; -- no one is proccesing it now

COMMIT;

这里的关键 -SERIALIZABLE只有一个事务可以成功更新记录(所有其他并发SERIALIZABLE更新都将失败ERROR: could not serialize access due to concurrent update)。

于 2013-01-11T15:13:00.180 回答
0

您将需要记录正在以某种方式处理行的事实。您还需要处理并发尝试,将它们标记为正在处理,并通过将它们发送到您的 ERP 系统来处理失败。

您可能会发现SELECT ... FOR UPDATE对于获取一组行并同时锁定它们以防止更新很有用。一种方法可能是让每个线程选择一个目标行,尝试将其 ID 添加到“处理”表中,然后在您更新 added_customer 的同一事务中将其删除。

如果一个线程没有获取候选行,或者插入失败,那么它只需要短暂休眠并重试。如果出现任何严重错误,那么您应该在“处理”表中留下可以检查/更正的行。

当然,另一种选择是只获取一组候选行并为每个与 ERP 通信的单独的进程/线程生成一个单独的进程/线程。这使数据库保持单线程获取,同时允许 ERP 的多个通道。

于 2013-01-11T14:52:45.560 回答