当前位置: 首页 > 知识库问答 >
问题:

处理PostgreSQL表的并发进程

滑弘扬
2023-03-14

我有一个简单的过程,需要处理一个表的记录,理想情况下运行多个流程实例,而不处理同一记录。我在MySQL中这样做的方式相当常见(尽管我认为令牌字段更像是一种黑客行为):

向表中添加几个字段:

CREATE TABLE records (
    id INTEGER PRIMARY KEY AUTO_INCREMENT,
    ...actual fields...

    processed_at DATETIME DEFAULT NULL,
    process_token TEXT DEFAULT NULL
);

然后是一个简单的处理脚本:

process_salt = md5(rand()) # or something like a process id

def get_record():
    token = md5(microtime + process_salt)
    db.exec("UPDATE records SET process_token = ?
             WHERE processed_at IS NULL LIMIT 1", token)
    return db.exec("SELECT * FROM records WHERE token = ?", token)

while (row = get_record()) is valid:
    # ...do processing on row...

    db.exec("UPDATE records SET processed_at = NOW(), token = NULL
             WHERE id = ?", row.id)

我正在使用PostgreSQL数据库的系统中实现这样的过程。我知道Pg在锁定方面可以被认为是比MySQL更成熟的,这要归功于MVCC - 我可以在Pg中使用行锁定或其他一些功能而不是令牌字段吗?

共有2个答案

方安怡
2023-03-14

您可以使用<代码>选择...FOR UPDATE NOWAIT,它将获得该行上的排他锁,或者如果该行已被锁定,则报告错误。

笪健
2023-03-14

这种方法适用于PostgreSQL,但它往往会非常低效,因为你要更新每行两次 - 每次更新需要两个事务,两个提交。通过使用commit_delay并可能禁用synchronous_commit,可以在一定程度上减轻其成本,但除非您在存储子系统上具有非易失性回写缓存,否则它仍然不会很快。

更重要的是,由于您正在提交第一次更新,因此无法区分仍在工作的工作人员和崩溃的工作人员之间的区别。如果所有工作线程都在本地计算机上,则可以将令牌设置为工作线程的进程 ID,然后偶尔扫描丢失的 PID,但这很麻烦且容易出现争用条件,更不用说 pid 重用的问题了。

我建议你采用一个真正的队列解决方案来解决这些问题,比如ActiveMQ、RabbitMQ、ZeroMQ等等。PGQ也可能是非常重要的。

在事务性关系数据库中进行队列处理应该很容易,但在实践中,很难做好并正确处理。大多数“解决方案”乍一看是合理的,但在详细检查时,它们实际上是序列化了所有工作(因此,在任何给定时间,许多队列工作者中只有一个在做任何事情)。

 类似资料:
  • 我看到公司中的一个应用程序使用 JMS 进行并发调用。该应用程序是在Spring编写的Web服务。这将进行许多外部调用。当收到操作请求时,它会将许多消息发布到JMS队列,MDB处理这些消息。然后,应用程序整理所有响应,将其映射回其数据模型并返回响应。我过去曾使用JMS进行火灾和遗忘调用,但我无法弄清楚应用程序如何等待来自JMS队列的响应。请问您能解释一下是否有办法吗?

  • 如果一个属性被配置为并发标记,那么在保存属性记录的期间 EF 将会制止其他用户修改该属性在数据库中的值。 提示 你可以在 GitHub 上查阅当前文章涉及的代码样例。 EF Core 是如何处理并发的 关于 Entity Framework Core 是如何处理并发的详细描述请查阅 并发标记。 解决并发冲突 解决并发冲突需要使用算法来将当前用户的挂起更改与数据库变更合并。具体的方法根据不同的应用程

  • 1.【强制】 获取单例对象需要保证线程安全,其中的方法也要保证线程安全。 说明: 资源驱动类、工具类、单例工厂类都需要注意。 2.【强制】 创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。 正例: public class TimerTaskThread extends Thread { public TimerTaskThread() { super.setN

  • 我附上了一个应用程序的示例代码,它在我的Core i3 370M笔记本电脑上(Win 7 64bit,Java 1.8.0.4564bit)在大约20秒内重现了这个问题。这个应用程序读取识别文本蕴涵(RTE)语料库的XML文件,然后使用标准Java并发类同时解析所有句子。本地RTE XML文件的路径需要作为命令行参数给出。在我的测试中,我使用了以下公开的XML文件:http://www.nist.

  • 并发请求处理 我创建了一个服务器,并使用s.listenandserve()来处理请求。据我所知,这些请求是同时送达的。我使用一个简单的处理程序来检查它: 我看到,如果我发送了几个请求,我将看到所有的“1”出现,只有在一秒钟后所有的“2”出现。但是如果删除Hibernate行,我会看到程序在完成前一个请求之前从不启动请求(输出为1 2 1 2 1 2...)。所以我不明白,如果它们是并发的还是不是

  • 问题内容: 当前,我们在数据层中使用JDBC,并计划用hibernate代替它。我是Hibernate的新手,不确定Hibernate如何处理并发。如果我们使用spring进行事务管理,有人可以解释一下我如何处理并发更新:通过hibernate(在内存中进行hibernate的自动版本管理),或者我必须将version列放入数据库中以手动处理并发更新。 问题答案: 无论你是否使用Spring进行事