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
这将防止并发数据修改。
考虑以下代码
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
这将防止并发数据修改。