go语言 go-redis watch实例

发布于:2024-04-26 ⋅ 阅读:(27) ⋅ 点赞:(0)

讲一下对watch的理解

在redis中watch是通过加了乐观锁的方法先获取事务执行前key值,如果在开始执行事务时检测到由于并发key被其他客户端修改了,就会终止事务

redis-cli //启动连接redis

WATCH counter//watch监听 counter

MULTI//如果counter 没有变化就开启事务

INCR counter//让counter自增
 
EXEC//提交事务

如果用go-redis实现就是这样的

var rdb *redis.Client
var ctx = context.Background() //上下文
/*
这部分代码创建了一个 Redis 客户端实例,连接到本地的 Redis 服务器。在实际应用中,
你可能需要根据实际情况配置 Redis 的地址、密码和数据库。
*/
func init() {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "",
		DB:       0,
	})
}

	// 定义一个回调函数,用于处理事务逻辑
	fn := func(tx *redis.Tx) error {
		// 先查询下当前watch监听的key的值
		v, err := tx.Get(ctx, "key").Int()
		if err != nil && err != redis.Nil {
			return err
		}
		// 这里可以处理业务
		v++

		// 如果key的值没有改变的话,Pipelined函数才会调用成功
		_, err = tx.Pipelined(ctx, func(pipe redis.Pipeliner) error {
			// 在这里给key设置最新值
			pipe.Set(ctx, "key", v, 0)

			result, _ := tx.Get(ctx, "key").Result()

			fmt.Println(result+" ", v)
			return nil
		})
		return err
	}

	// 使用Watch监听一些Key, 同时绑定一个回调函数fn, 监听Key后的逻辑写在fn这个回调函数里面
	// 如果想监听多个key,可以这么写:client.Watch(ctx,fn, "key1", "key2", "key3")
	rdb.Watch(ctx, fn, "key")

其中watch即使对key值的监听,fn回调函数相当于如果key没有发生修改要执行的事务逻辑

下面这段代码为redis的连接实例化一个rdb客户端
var rdb *redis.Client
var ctx = context.Background() //上下文
/*
这部分代码创建了一个 Redis 客户端实例,连接到本地的 Redis 服务器。在实际应用中,
你可能需要根据实际情况配置 Redis 的地址、密码和数据库。
*/
func init() {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "",
		DB:       0,
	})
}

watch的执行逻辑

在go-redis中,当你使用Watch函数并传入回调函数时,库的内部实现大致执行了以下步骤:

  1. 监控阶段:调用Watch函数时,它会首先为指定的键设置监视点(WATCH命令)。这个监视确保如果在事务执行前这些键被修改,事务将不会执行。

  2. 执行回调函数:如果在执行事务的过程中监视的键未被修改,则Watch函数会创建一个新的事务(MULTI命令),并执行提供的回调函数。在回调函数内,你可以向事务中添加想要执行的命令。

  3. 事务提交:回调函数执行完后,如果没有出现错误,事务将会被提交(EXEC命令)。如果在执行回调函数的过程中出现了错误,或者监视的键值被修改,则事务将会被取消(DISCARD命令)。

  4. 重试逻辑:如果由于WATCH监视的键被修改而导致事务失败,Watch方法会自动重新执行回调函数,直到事务成功提交或达到某些终止条件(例如最大尝试次数)。