9、并发读取同一份数据,保证数据的正确性

38 阅读2分钟

该测试源文件在我的github开源的gin-scaffold上:github.com/linbe-ff/gi… 有兴趣的同学可以看看哦。 目录:pkg/redis/eample_test.go

1、加全局锁。


func TestRedisLock(t *testing.T) {
    // 初始化配置和日志
    config.InitConfig("/home/breelk/workspace/src/gin-scaffold/config.yaml")
    logger.InitLogger()
    Init()
    rdbClient := GetClient()

    wg := sync.WaitGroup{}

    shareValue := 1
    ctx := context.Background()

    for i := 0; i < 5; i++ {
       wg.Add(1)
       go func() {
          defer func() {
             wg.Done()
             logger.Logger.Info("任务结束")
             rdbClient.UnLock(ctx, "lock1", "lock1")
          }()
          // 自旋锁
          for {
             ok, err := rdbClient.Lock(ctx, "lock1", "lock1", 30*time.Second)
             if err != nil {
                time.Sleep(3 * time.Second)
                logger.Logger.Error("redis 数据库获取数据失败")
                continue
             }
             if !ok {

                time.Sleep(3 * time.Second)
                logger.Logger.Error("redis 获取锁失败")
                continue
             }
             // 获取锁
             break
          }

          logger.Logger.Info(fmt.Sprintf("src value %d ,after value %d", shareValue, shareValue+1))
          shareValue++
       }()
       wg.Wait()
    }
    //  2025-07-04T23:57:08.920+0800   INFO   redis/eample_test.go:62    src value 1 ,after value 2
    //  2025-07-04T23:57:08.920+0800   INFO   redis/eample_test.go:41    任务结束
    //  2025-07-04T23:57:11.922+0800   ERROR  redis/eample_test.go:55    redis 获取锁失败
    //  2025-07-04T23:57:11.922+0800   INFO   redis/eample_test.go:62    src value 2 ,after value 3
    //  2025-07-04T23:57:11.922+0800   INFO   redis/eample_test.go:41    任务结束
    //  2025-07-04T23:57:11.922+0800   INFO   redis/eample_test.go:62    src value 3 ,after value 4
    //  2025-07-04T23:57:11.923+0800   INFO   redis/eample_test.go:41    任务结束
    //  2025-07-04T23:57:11.923+0800   INFO   redis/eample_test.go:62    src value 4 ,after value 5
    //  2025-07-04T23:57:11.923+0800   INFO   redis/eample_test.go:41    任务结束
    //  2025-07-04T23:57:14.925+0800   ERROR  redis/eample_test.go:55    redis 获取锁失败
    //  2025-07-04T23:57:14.925+0800   INFO   redis/eample_test.go:62    src value 5 ,after value 6
}

2、使用队列让请求串行化。
```go
func TestChanel(t *testing.T) {
    // 初始化配置和日志
    config.InitConfig("/home/breelk/workspace/src/gin-scaffold/config.yaml")
    logger.InitLogger()
    var wg sync.WaitGroup
    shareValue := 1
    lockChan := make(chan struct{}, 1) // 在项目中是全局的chan

    lockChan <- struct{}{} // 获取锁-初始化
    for i := 0; i < 5; i++ {
       wg.Add(1)
       go func() {
          defer func() {
             wg.Done()
             logger.Logger.Info("任务结束")
             // 释放锁
             lockChan <- struct{}{}
          }()
          // 获取锁
          <-lockChan

          logger.Logger.Info(fmt.Sprintf("src value %d, after value %d", shareValue, shareValue+1))
          shareValue++
       }()
    }
    wg.Wait()

    //  2025-07-04T23:56:38.307+0800   INFO   redis/eample_test.go:102   src value 1, after value 2
    //  2025-07-04T23:56:38.308+0800   INFO   redis/eample_test.go:95    任务结束
    //  2025-07-04T23:56:38.308+0800   INFO   redis/eample_test.go:102   src value 2, after value 3
    //  2025-07-04T23:56:38.308+0800   INFO   redis/eample_test.go:95    任务结束
    //  2025-07-04T23:56:38.308+0800   INFO   redis/eample_test.go:102   src value 3, after value 4
    //  2025-07-04T23:56:38.308+0800   INFO   redis/eample_test.go:95    任务结束
    //  2025-07-04T23:56:38.308+0800   INFO   redis/eample_test.go:102   src value 4, after value 5
    //  2025-07-04T23:56:38.308+0800   INFO   redis/eample_test.go:95    任务结束
    //  2025-07-04T23:56:38.308+0800   INFO   redis/eample_test.go:102   src value 5, after value 6

}