golang gorm 2 中使用 lock for update 锁

发布时间: 2021-08-22 17:04:45 作者: 大象笔记

查了一下 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 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 了!

我是一名山东烟台的开发者,联系作者