golang gorm 2 中使用 lock for update 锁

文章目录

    查了一下 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 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式