redis 事务处理命令
- MULTI:开启一个事务
- EXEC:事务执行,将一次性执行事务内的所有命令
- DISCARD:取消事务
使用 WATCH+MULTI 的方式来实现乐观锁
WATCH:监控一个或多个键,如果事务执行前某个键发生了改动,那么事务也会被打断
UNWATCH:取消 WATCH 命令对所有键的监视
使用go-redis package模拟用户抢票的流程
- 开启多个goroutine模拟并发抢票
- go-redis
TxPipelined
执行事务 - go-redis
client.Watch
监控某个键
package mainimport ( "errors" "fmt" "sync" "github.com/go-redis/redis/v7")func main() { client := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password set DB: 0, // use default DB }) key := "ticket_count" client.Set(key, "5", 0).Err() val, _ := client.Get(key).Result() fmt.Println("current ticket_count key val: ", val) getTicket(client, key)}func runTx(key string, id int) func(tx *redis.Tx) error { txf := func(tx *redis.Tx) error { n, err := tx.Get(key).Int() if err != nil && err != redis.Nil { return err } if n == 0 { return errors.New("票没了") } // actual opperation (local in optimistic lock) n = n - 1 // runs only if the watched keys remain unchanged _, err = tx.TxPipelined(func(pipe redis.Pipeliner) error { // pipe handles the error case pipe.Set(key, n, 0) return nil }) return err } return txf}func getTicket(client *redis.Client, key string) { routineCount := 8 var wg sync.WaitGroup wg.Add(routineCount) for i := 0; i < routineCount; i++ { go func(id int) { defer wg.Done() for { err := client.Watch(runTx(key, id), key) if err == nil { fmt.Println(id, "成功") return } else if err.Error() == "票没了" { fmt.Println(id, "票没了") return } else { fmt.Println(err, "retry") } } }(i) } wg.Wait()}
Github code: https://github.com/defp/redis…
current ticket_count key val: 57 成功6 成功redis: transaction failed retryredis: transaction failed retryredis: transaction failed retryredis: transaction failed retryredis: transaction failed retryredis: transaction failed retryredis: transaction failed retry3 成功redis: transaction failed retryredis: transaction failed retryredis: transaction failed retryredis: transaction failed retry2 成功redis: transaction failed retryredis: transaction failed retryredis: transaction failed retryredis: transaction failed retry5 成功redis: transaction failed retryredis: transaction failed retryredis: transaction failed retry4 票没了1 票没了0 票没了
links
- How to create Redis Transaction in Go using go-redis/redis package? – Stack Overflow
- redis package · pkg.go.dev
- Redis 写缓存
- defp/redis-watch-multi-exec-demo
- 42丨如何使用Redis来实现多用户抢票问题
文章来源:智云一二三科技
文章标题:Redis optimistic lock with golang demo
文章地址:https://www.zhihuclub.com/5299.shtml
评论已关闭
Hi, i feel that i saw you visited my website so i got here to go back the favor?.I am trying to in finding things to improve my site!I guess its ok to use some of your concepts!!