插入和更新中的Postgresql死锁

时间:2016-06-09 11:47:40

标签: postgresql go database-deadlocks

以下是postgres日志

Process 10396 waits for RowShareLock on relation 17204 of database 16384; blocked by process 10377.
Process 10377 waits for ShareLock on transaction 149848948; blocked by process 10396.
Process 10396: insert into "completed_jobs" ("id", ....... "limitation_code") values ($1, ...... $22) returning "id"
Process 10377: UPDATE jobs SET status='pending', updated_at=$1 WHERE id=$2

我是从郎朗执行的。所以这是在分布式环境中。

更新是正常的执行,

    _, err = tx.Exec("UPDATE jobs SET status='pending', updated_at=$1 WHERE id=$2", time.Now().UTC(), job.Id)
    if err != nil {
        log.Println(getMessagePrefix(job, nil), "Error updating job status to pending", err)
    }
    err = tx.Commit()

插入是在事务中,

tx, _ := db.Begin()
tx.Exec("UPDATE jobs SET status=$1 WHERE id=$6", status)
tx.Exec("INSERT INTO completed_jobs SELECT * FROM jobs WHERE id=$1", job.Id)
tx.Exec("DELETE FROM jobs WHERE id=$1", job.Id)
err := tx.Commit()

1 个答案:

答案 0 :(得分:0)

在作业排队中,我通常使用以下策略来防止多个进程尝试访问相同的作业。通常,您需要跨事务控制来处理此问题。

  • 咨询锁是跨事务锁定自由锁。这意味着您可以在将进程内作业返回到客户端之前将其排除。这也避免了待处理的状态要求。
  • 使用随机ID进行短交易,以防止多个进程可能遇到相同的ID。如果使用索引,这也很重要,因为如果你最终得到长时间运行的事务处理,你可以在索引的头部获得大量的死元组。

作业队列系统中的并发性会带来大量问题。但是那两个解决了最糟糕的问题。