2026-06-30 13:37:01
Redis事务通过MULTI/EXEC、WATCH等命令实现,确保多命令的原子性执行或乐观锁控制。以下是关键点解析及代码示例说明:
1. 事务基础:MULTI/EXECRedis单线程特性保证单个命令原子性,但需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. 乐观锁:WATCHWATCH监视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(无冲突时)关键注意事项原子性范围:
MULTI/EXEC确保事务内命令按序执行,但不保证隔离性(其他客户端命令可能穿插在EXEC前后)。
WATCH提供乐观锁,需主动处理TxFailedErr重试。
性能优化:
TxPipelined自动包裹MULTI/EXEC,减少RTT(网络往返时间)。
避免长时间事务(如示例中的time.Sleep),否则会阻塞其他命令。
错误处理:
检查redis.TxFailedErr判断是否因乐观锁失败。
设置合理的重试次数(如示例中的routineCount)。
通过合理使用MULTI/EXEC和WATCH,Redis事务能满足大多数原子性或并发控制需求,但需注意其与关系型数据库事务的差异(如无回滚机制)。