查了一下 golang gorm 2 确实支持 lock for update。文档:
https://gorm.io/zh_CN/docs/advanced_query.html#Locking-FOR-UPDATE
db.Clauses(clause.Locking{Strength: "UPDATE"}).Find(&users)
但由于 for update 必须在事务中使用,所以,还需要看看 gorm 事务的写法。
lock for update 与 share 的区别
参考 使用 Laravel sharedLock 与 lockForUpdate 进行数据表行锁
- sharedLock 不会阻止其他 transaction 读取同一行
- lockForUpdate 会阻止其他 transaction 读取同一行
sharedLock locks only for write, lockForUpdate also prevents them from being selected
lock for update 何时释放锁
事务结束时。
只有在第一个终端执行
commit;
第二个终端才能得到数据返回。
需要注意的是,发起者必须在 transaction 里上锁才有效,如果不是在 transaction 中,上锁是无效的。但是,第二个人无论是不是在 transaction 里,都会被锁。
Error 1205: Lock wait timeout exceeded; try restarting transaction
实际测试时,我发现在对一行记录加锁,读出来,再更新数据时,报超时错误:
Error 1205: Lock wait timeout exceeded; try restarting transaction
出错代码如下:
var user models.User
models.DB.Transaction(func(tx *gorm.DB) error {
// 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
// 返回任何错误都会回滚事务
var err error
err = tx.Clauses(clause.Locking{Strength: "UPDATE"}).
Where("status", 0).
Order("id asc").
First(&user).
Error
if err != nil {
log.Println(err)
return err
}
models.DB.Model(&user).Update("status", 1) // 报错
// 返回 nil 提交事务
return nil
})
更新状态那行报错。
修复方法:
将 db 换成 tx 就可以了。。。
tx.Model(&user).Update("status", 1)
忘记了事务中必须统一使用 tx 替换 db 了!
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式