redis事务

兄弟们在线说明下,redis事务
最新回答
爱情的模样

2026-06-30 13:37:01

Redis事务通过MULTI/EXEC、WATCH等命令实现,确保多命令的原子性执行或乐观锁控制。以下是关键点解析及代码示例说明:

1. 事务基础:MULTI/EXEC

Redis单线程特性保证单个命令原子性,但需MULTI/EXEC确保多命令连续执行不被打断。示例代码(TxPipeline/TxPipelined):

// TxPipeline方式pipe := rdb.TxPipeline()incr := pipe.Incr(ctx, "tx_pipeline_counter")pipe.Expire(ctx, "tx_pipeline_counter", time.Hour)_, err := pipe.Exec(ctx)// TxPipelined方式(推荐,自动包裹MULTI/EXEC)var incr2 *redis.IntCmd_, err = rdb.TxPipelined(ctx, func(pipe redis.Pipeliner) error { incr2 = pipe.Incr(ctx, "tx_pipeline_counter") pipe.Expire(ctx, "tx_pipeline_counter", time.Hour) return nil})

等效Redis命令:

MULTIINCR tx_pipeline_counterEXPIRE tx_pipeline_counter 3600EXEC2. 乐观锁:WATCH

WATCH监视key,若事务执行前key被修改,则事务失败。需结合重试机制处理冲突。示例代码(WATCH + TxPipelined):

func watchDemo(ctx context.Context, key string) error { return rdb.Watch(ctx, func(tx *redis.Tx) error { // 获取当前值 n, err := tx.Get(ctx, key).Int() if err != nil && err != redis.Nil { return err } // 模拟耗时操作(期间若key被修改,事务失败) time.Sleep(5 * time.Second) // 事务提交 _, err = tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error { pipe.Set(ctx, key, n+1, time.Hour) return nil }) return err }, key) // 监视的key}

失败场景:若5秒内其他客户端修改key,返回错误redis: transaction failed。

3. 完整示例:乐观锁实现INCR

通过WATCH和重试机制实现高并发安全的自增操作:

const routineCount = 100func increment(key string) error { txf := func(tx *redis.Tx) error { n, err := tx.Get(key).Int() if err != nil && err != redis.Nil { return err } n++ // 事务提交 _, err = tx.Pipelined(func(pipe redis.Pipeliner) error { pipe.Set(key, n, 0) return nil }) return err } // 重试机制 for retries := routineCount; retries > 0; retries-- { err := rdb.Watch(txf, key) if err != redis.TxFailedErr { // 非乐观锁冲突错误 return err } } return errors.New("max retries reached")}// 并发测试var wg sync.WaitGroupwg.Add(routineCount)for i := 0; i < routineCount; i++ { go func() { defer wg.Done() if err := increment("counter3"); err != nil { fmt.Println("error:", err) } }()}wg.Wait()// 验证结果n, _ := rdb.Get("counter3").Int()fmt.Println("final value:", n) // 预期输出100(无冲突时)关键注意事项
  1. 原子性范围:

    MULTI/EXEC确保事务内命令按序执行,但不保证隔离性(其他客户端命令可能穿插在EXEC前后)。

    WATCH提供乐观锁,需主动处理TxFailedErr重试。

  2. 性能优化:

    TxPipelined自动包裹MULTI/EXEC,减少RTT(网络往返时间)。

    避免长时间事务(如示例中的time.Sleep),否则会阻塞其他命令。

  3. 错误处理:

    检查redis.TxFailedErr判断是否因乐观锁失败。

    设置合理的重试次数(如示例中的routineCount)。

通过合理使用MULTI/EXEC和WATCH,Redis事务能满足大多数原子性或并发控制需求,但需注意其与关系型数据库事务的差异(如无回滚机制)。