go使用redis事务时进行回滚操作

起因

在学习redis的过程中,因为教程都是java编写的,但自身学习的是go语言,所以想用go实现一下,本次使用的库是go-redis,在github上可以看到详细教程。

经过

由于教程是编写一个秒杀功能,即并发对商品进行抢购,会出现一个超卖的问题,所以需要使用redis的watch对数据进行监控,一旦被修改进行回滚,也就是redis的乐观锁,但找了网上的教程都实现不了,最后看了官方示例以及各种网上操作尝试成功了,所以将代码分享出来,以免走弯路。
使用的是gin框架

func seckill(c *gin.Context) {
	ctx := context.Background()
	//获取pid和uid
	productId := c.Query("productId")
	userId := c.Query("userId")
	//判断是否为空
	if productId == "" || userId == "" {
		c.JSON(400, gin.H{"msg": "bad request"})
		return
	}
	//组装商品key和用户key
	scProdKey := "sc:" + productId
	scUserKey := "sc:user:" + productId

	err := client.Watch(ctx, func(tx *redis.Tx) error {

		//查看活动是否开始
		val, err := tx.Exists(ctx, scProdKey).Result()
		if err != nil {
			return errors.New(err.Error())
		}
		if val == 0 {
			return errors.New("活动还没开始")
		}

		//是否还有库存
		prodNum, err := tx.Get(ctx, scProdKey).Int()
		if err != nil {
			return errors.New(err.Error())
		}
		if prodNum <= 0 {
			return errors.New("库存已卖完")
		}

		_, err = tx.TxPipelined(ctx, func(p redis.Pipeliner) error {
			err := p.Decr(ctx, scProdKey).Err()
			if err != nil && err != redis.Nil {
				return err
			}
			err = p.SAdd(ctx, scUserKey, userId).Err()
			if err != nil && err != redis.Nil {
				return err
			}
			return nil
		})
		return err
	}, scProdKey)
	if err != nil {
		c.JSON(400, gin.H{"msg": err.Error()})
		return
	}

	c.JSON(200, gin.H{"msg": "抢购成功"})
}

如果需要解决库存问题,还需要加上悲观锁或者使用lua脚本进行实现,这里就不进行讲解了。
希望能帮到你 😃

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值