文章目录
悲观锁
是一种在并发控制中常用的策略,主要用于防止数据在并发访问时发生冲突
不允许别人访问它 处于一个悲观的状态
SELECT … **FOR UPDATE:**在SQL语句中使用SELECT … FOR UPDATE可以锁定查询结果集中的数据行,确保其他事务无法对这些行进行修改(包括INSERT、UPDATE和DELETE操作)。直到当前事务提交或回滚,锁才会被释放。
优点:
能够确保数据的一致性和完整性,避免并发冲突。
实现相对简单,不需要复杂的版本控制机制。
缺点:
性能开销大,特别是在高并发场景下可能影响系统性能。
容易产生死锁问题,如果锁的管理不当可能会导致系统无法继续运行。
可能导致资源浪费,如果事务长时间持有锁而不释放,其他事务将无法访问被锁定的数据。
// Sell 扣减库存 悲观锁实现
func (c *Server) Sell(ctx context.Context, in *proto.SellInfo) (*proto.Empty, error) {
//开启本地事务
//并发情况下出现超卖的问题 要确保他的一致性 一起成功或者一起失败
tx := global.Db.Begin()
if tx.Error != nil {
return nil, status.Errorf(codes.Internal, "事务开启失败")
}
for _, info := range in.GoodsInfo {
//定义一个库存存放的结构体
//查询是否有这个库存
var inv model.Inventory
//悲观锁
result := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where(&model.Inventory{GoodsId: info.GoodsId}).First(&inv)
if result.RowsAffected == 0 || result.Error != nil {
tx.Rollback() //事务回滚
return nil, status.Errorf(codes.Internal, "库存详情查询失败")
}
if inv.Number < info.Num {
tx.Rollback() //事务回滚
return nil, status.Errorf(codes.Internal, "库存不足")
}
inv.Number -= info.Num
res := tx.Save(&inv)
if res.Error != nil {
tx.Rollback() //事务回滚
return nil, status.Errorf(codes.Internal, "设置库存失败")
}
}
tx.Commit()
return &proto.Empty{}, nil
}
在gorm中如何实现悲观锁
Clauses(clause.Locking{Strength: “UPDATE”})