postgres 中的事务锁定行还是仅 select?

Does transaction lock row in postgres or only select?

考虑以下代码

func main() {

    ctx := context.Background()
    tx, err := db.BeginTx(ctx, nil)

    row := tx.QueryRow("SELECT timestamp, my_id, my_value FROM my_table ORDER BY timestamp ASC limit 1 ")
    var my_id int
    var my_time time.Time
    var my_value string
    err = row.Scan(&my_time, &my_id, &my_value)
    if err != nil {
        tx.Rollback()
        return
    }
    _, err = tx.ExecContext(ctx, "UPDATE my_table SET status = 'start' WHERE my_id = ", my_id)
    if err != nil {
        tx.Rollback()
        return
    }

    err = tx.Commit()
    if err != nil {
        log.Fatal(err)
    }

    // do something with my_value that takes a long time
}

其中 select 时间戳最旧的行并将状态设置为 start 并使用 return 值执行某些操作,我 运行 此事务在多个threaded/server 环境,如何确保每个线程都获得唯一的 my_id 并且没有两个线程处理相同的 my_id

我认为 select 语句不会锁定在第一个 select 期间得到 returned 的行,因此多个线程可以尝试更新同一行。

我可以将更新语句修改为

UPDATE my_table SET status = 'start' WHERE my_id =  AND status <> `start`

但是我不得不重新select另一个id,有什么办法可以避免吗?

使用悲观锁在读取时对行加UPDATE锁:

SELECT ... FOR UPDATE

这将防止并发数据修改。