为什么悲观的锁在PSQL中对我不起作用?该代码并非并发,我期望的是

发布于 2025-01-31 22:28:18 字数 1108 浏览 3 评论 0原文

我正在尝试获取和更新一列,并需要此过程以并发。因此,我通过选择更新的选择行级锁仍然不符合预期。此列只是一个随机列,而不是主键或外键。

我将其更改为乐观的锁定,但它奏效了,但我试图理解为什么这不起作用。我在下面多次运行此代码,并且它的行为与单独运行的次数相同的次数并没有相同的方式。

_, err = s.xStore.ManageTransaction(func(ctx context.Context, tx *sqlx.Tx) (interface{}, error) {
                _, err := tx.Exec("set transaction isolation level repeatable read")
                if err != nil {
                    return nil, err
                }
                c, err = s.xStore.GetForUpdate(x) 
                //Some calculations
                _ = s.xStore.Update(c)
                return nil, nil
            })
            return
    }()
}

这是我的获取查询,其中a for更新以锁定行。

func (s *xStore) GetForUpdate(id string) (*model.X, error) {
    query := `
        SELECT * FROM things where id = $1 FOR UPDATE`

    _, err := s.db.Exec(query, id)
    if err != nil {
        return nil, err
    }

    var x model.X
    err := s.db.Get(&x, query, id)
    err = s.db.Get(&x, query, id)
    if err != nil {
        return nil, err
    }
    return &x, nil
}

I am trying to get and update a column and need this process to be concurrent. Therefore, I do a row level lock via SELECT FOR UPDATEand then do my calculations and then do my update, all within a transaction with isolation level repeatable read.However, this is still not concurrent as expected. This column is just a random column and not the primary or a foreign key.

I changed this to optimistic locking after and that worked but I am trying to understand why this did not work. I ran this code below concurrently multiple times and it did not behave the same way as it would have if I individually ran it the same number of times.

_, err = s.xStore.ManageTransaction(func(ctx context.Context, tx *sqlx.Tx) (interface{}, error) {
                _, err := tx.Exec("set transaction isolation level repeatable read")
                if err != nil {
                    return nil, err
                }
                c, err = s.xStore.GetForUpdate(x) 
                //Some calculations
                _ = s.xStore.Update(c)
                return nil, nil
            })
            return
    }()
}

Here is my Get query with a FOR UPDATE to lock the row.

func (s *xStore) GetForUpdate(id string) (*model.X, error) {
    query := `
        SELECT * FROM things where id = $1 FOR UPDATE`

    _, err := s.db.Exec(query, id)
    if err != nil {
        return nil, err
    }

    var x model.X
    err := s.db.Get(&x, query, id)
    err = s.db.Get(&x, query, id)
    if err != nil {
        return nil, err
    }
    return &x, nil
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

哆兒滾 2025-02-07 22:28:18

您的代码正在执行不同交易中的查询,
创建新的(db.begintx)或提供在某种程度上提供的使用,例如:

  • rows:= tx.query(您的查询
  • 执行一些calc
  • tx.execcontext
  • tx.commit

(请参阅 https://go.dev/doc/database/execute-execute-transactions

Your code is executing queries in different transactions ,
create new one (db.BeginTx) or use provided someway like :

  • rows := tx.Query( your query )
  • do some calc
  • tx.ExecContext
  • tx.Commit

(Referring to https://go.dev/doc/database/execute-transactions )

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文