在 Yii 2.0 中,Redis ActiveRecord 出现主键 ID 重复的情况的分析解决

1、请求接口,响应参数中资源总数量为 30 个。包含 id 等于 37918 的资源是重复的。总计为 2 个。如图1

请求接口,响应参数中资源总数量为 30 个。包含 id 等于 37918 的资源是重复的。总计为 2 个。

图1

{
  "code": 10000,
  "message": "获取 CMC 用户列表成功",
  "data": {
    "items": [
      {
        "user_birthday": "1990-01-01",
        "login_name": "xianwanzhou",
        "add_time": "2020-03-31 09:41:07",
        "user_email": "",
        "group_id": "643d80843ae23bcfa95b75bae30a7656",
        "id": "37918",
        "user_pic": "http://uploads.cmc.lzgbdst.com/uploads/cmc_user_avatar/default_header.png",
        "update_time": "2020-03-31 09:43:16",
        "is_open": "1",
        "user_nick": "鲜万州",
        "user_mobile": "15208396209",
        "user_token": "6a1de11e594d61790963eaaf1d9bee8d",
        "user_chat_id": "f98e3b834f577cc3d83d74323cd3094d",
        "user_type": "2",
        "user_sex": "2"
      },
      {
        "user_birthday": "1990-01-01",
        "login_name": "xianwanzhou",
        "add_time": "2020-03-31 09:41:07",
        "user_email": "",
        "group_id": "643d80843ae23bcfa95b75bae30a7656",
        "id": "37918",
        "user_pic": "http://uploads.cmc.lzgbdst.com/uploads/cmc_user_avatar/default_header.png",
        "update_time": "2020-03-31 09:43:16",
        "is_open": "1",
        "user_nick": "鲜万州",
        "user_mobile": "15208396209",
        "user_token": "6a1de11e594d61790963eaaf1d9bee8d",
        "user_chat_id": "f98e3b834f577cc3d83d74323cd3094d",
        "user_type": "2",
        "user_sex": "2"
      }
    ],
    "_links": {
      "self": {
        "href": "http://pcsapi.cmc.lzgbdst.com/v1/cmc-users?login_id=7309cba1c93fc0a80663007612b784b8&login_tid=25f49c543b8ec31c6d905def0ad99913&per-page=30&page=1"
      }
    },
    "_meta": {
      "totalCount": 30,
      "pageCount": 1,
      "currentPage": 1,
      "perPage": 30
    }
  }
}

2、查看模型类,/common/models/redis/cmc_console/User.php

<?php

namespace common/models/redis/cmc_console;

use Yii;
use common/components/redis/ActiveRecord;

/**
 * This is the model class for table "{{%user}}".
 *
 * @property string $id
 * @property string $group_id
 * @property string $login_name
 * @property string $user_token
 * @property string $user_nick
 * @property string $user_pic
 * @property string $user_mobile
 * @property string $user_email
 * @property string $user_sex
 * @property string $user_birthday
 * @property string $user_type
 * @property string $user_chat_id
 * @property string $is_open
 * @property string $add_time
 * @property string $update_time
 */
class User extends ActiveRecord
{
    /**
     * @return array the list of attributes for this record
     */
    public function attributes()
    {
        return ['id', 'group_id', 'login_name', 'user_token', 'user_nick', 'user_pic', 'user_mobile', 'user_email', 'user_sex', 'user_birthday', 'user_type', 'user_chat_id', 'is_open', 'add_time', 'update_time'];
    }
    
    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['id', 'group_id', 'login_name', 'user_token', 'user_nick', 'user_pic', 'user_mobile', 'user_email', 'user_sex', 'user_birthday', 'user_type', 'user_chat_id', 'is_open', 'add_time', 'update_time'], 'safe'],
        ];
    }
    
    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => Yii::t('model/redis/cmc-console/user', 'ID'),
            'group_id' => Yii::t('model/redis/cmc-console/user', 'Group ID'),
            'login_name' => Yii::t('model/redis/cmc-console/user', 'Login Name'),
            'user_token' => Yii::t('model/redis/cmc-console/user', 'User Token'),
            'user_nick' => Yii::t('model/redis/cmc-console/user', 'User Nick'),
            'user_pic' => Yii::t('model/redis/cmc-console/user', 'User Pic'),
            'user_mobile' => Yii::t('model/redis/cmc-console/user', 'User Mobile'),
            'user_email' => Yii::t('model/redis/cmc-console/user', 'User Email'),
            'user_sex' => Yii::t('model/redis/cmc-console/user', 'User Sex'),
            'user_type' => Yii::t('model/redis/cmc-console/user', 'User Type'),
            'user_birthday' => Yii::t('model/redis/cmc-console/user', 'User Birthday'),
            'user_chat_id' => Yii::t('model/redis/cmc-console/user', 'User Chat Id'),
            'is_open' => Yii::t('model/redis/cmc-console/user', 'Is Open'),
            'add_time' => Yii::t('model/redis/cmc-console/user', 'Add Time'),
            'update_time' => Yii::t('model/redis/cmc-console/user', 'Update Time'),
        ];
    }
}

3、查看 /common/components/redis/ActiveRecord.php ,定义了前缀,适用于所有 AR 键。

<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/02/05
 * Time: 9:47
 */

namespace common/components/redis;

use Yii;

class ActiveRecord extends /yii/redis/ActiveRecord
{
    /**
     * Declares prefix of the key that represents the keys that store this records in redis.
     * By default this method returns the class name as the table name by calling [[Inflector::camel2id()]].
     * For example, 'Customer' becomes 'customer', and 'OrderItem' becomes
     * 'order_item'. You may override this method if you want different key naming.
     * @return string the prefix to apply to all AR keys
     */
    public static function keyPrefix()
    {
        return Yii::$app->params['redisActiveRecord']['keyPrefix'] . parent::keyPrefix();
    }
}

4、打开 RedisDesktopManager,查看 用户 总数,确定为 29 个,如图2

打开 RedisDesktopManager,查看 用户 总数,确定为 29 个

图2

5、打开 RedisDesktopManager,确定主键值为 37918 的记录为 1 个,并未重复。如图3

打开 RedisDesktopManager,确定主键值为 37918 的记录为 1 个,并未重复。

图3

6、查看 pa:ar:user 的值,发现行 29、30 的值皆为 37918。由此确定,是此键的值导致了 id 等于 37918 的资源数等于 2 个。如图4

查看 pa:ar:user 的值,发现行 29、30 的值皆为 37918。由此确定,是此键的值导致了 id 等于 37918 的资源数等于 2 个。

图4

7、删除 pa:ar:user 的第 30 行,如图5

删除 pa:ar:user 的第 30 行

图5

8、再次请求接口,响应参数中资源总数量为 29 个。包含 id 等于 37918 的资源未重复。仅剩下 1 个。

{
  "code": 10000,
  "message": "获取 CMC 用户列表成功",
  "data": {
    "items": [
      {
        "user_birthday": "1990-01-01",
        "login_name": "xianwanzhou",
        "add_time": "2020-03-31 09:41:07",
        "user_email": "",
        "group_id": "643d80843ae23bcfa95b75bae30a7656",
        "id": "37918",
        "user_pic": "http://uploads.cmc.lzgbdst.com/uploads/cmc_user_avatar/default_header.png",
        "update_time": "2020-03-31 09:43:16",
        "is_open": "1",
        "user_nick": "鲜万州",
        "user_mobile": "15208396209",
        "user_token": "6a1de11e594d61790963eaaf1d9bee8d",
        "user_chat_id": "f98e3b834f577cc3d83d74323cd3094d",
        "user_type": "2",
        "user_sex": "2"
      }
    ],
    "_links": {
      "self": {
        "href": "http://pcsapi.cmc.lzgbdst.com/v1/cmc-users?login_id=7309cba1c93fc0a80663007612b784b8&login_tid=25f49c543b8ec31c6d905def0ad99913&per-page=29&page=1"
      }
    },
    "_meta": {
      "totalCount": 29,
      "pageCount": 1,
      "currentPage": 1,
      "perPage": 29
    }
  }
}

9、准备在本地环境复现一下 ID 主键重复的情况。请求接口,响应参数中资源总数量为 13 个。ID 主键未重复。如图6

准备在本地环境复现一下 ID 主键重复的情况。请求接口,响应参数中资源总数量为 13 个。ID 主键未重复。

图6

{
  "code": 10000,
  "message": "获取 CMC 用户列表成功",
  "data": {
    "items": [
      {
        "login_name": "13281105967",
        "update_time": "2019-12-11 14:28:26",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "13281105967",
        "user_sex": "2",
        "user_mobile": "13281105967",
        "user_type": "1",
        "is_open": "1",
        "user_chat_id": "ede7616c5e4232896453202cd0c3f7ec",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/20190219/1550570817-4LLQJJ.png",
        "id": "3",
        "add_time": "2018-04-26 10:05:28",
        "user_birthday": "1990-01-01",
        "user_email": "13281105967@chinamcloud.com",
        "user_token": "fb46626f0e71e423ca8ab4c750620a85"
      },
      {
        "login_name": "test10",
        "update_time": "2019-12-11 15:00:38",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "test10",
        "user_sex": "2",
        "user_mobile": "13980074657",
        "user_type": "2",
        "is_open": "1",
        "user_chat_id": "ce524778954bd10d5a0ff65dadc0354b",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
        "id": "4",
        "add_time": "2019-12-11 14:55:07",
        "user_birthday": "1990-01-01",
        "user_email": "",
        "user_token": "bc8daab7ba8620c132cdf4e5de1d4758"
      },
      {
        "login_name": "jmj12130003",
        "update_time": "2019-12-13 14:41:55",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "jmj1213",
        "user_sex": "2",
        "user_mobile": "18412130003",
        "user_type": "2",
        "is_open": "1",
        "user_chat_id": "84e1bb32ffa895e56d950bbfa24fefc7",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
        "id": "49",
        "add_time": "2019-12-13 14:41:55",
        "user_birthday": "1990-01-01",
        "user_email": "",
        "user_token": "ba0ca65da7c3048fd9d449bb0d21a39b"
      },
      {
        "login_name": "test11",
        "update_time": "2019-12-17 11:14:53",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "test11",
        "user_sex": "2",
        "user_mobile": "13980074650",
        "user_type": "2",
        "is_open": "1",
        "user_chat_id": "bc1650a6834fc490de65a4527dfc8ae5",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
        "id": "64",
        "add_time": "2019-12-17 11:14:53",
        "user_birthday": "1990-01-01",
        "user_email": "",
        "user_token": "04532bb62deb99bf229698c9e1a81da1"
      },
      {
        "login_name": "test12",
        "update_time": "2019-12-17 11:15:14",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "test12",
        "user_sex": "2",
        "user_mobile": "13980074651",
        "user_type": "2",
        "is_open": "1",
        "user_chat_id": "fa154673421e5a3731991498397d712d",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
        "id": "65",
        "add_time": "2019-12-17 11:15:14",
        "user_birthday": "1990-01-01",
        "user_email": "",
        "user_token": "bcdc9e3781180b7bc18bc0e38777a467"
      },
      {
        "login_name": "test13",
        "update_time": "2019-12-17 11:15:35",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "test13",
        "user_sex": "2",
        "user_mobile": "13980074652",
        "user_type": "2",
        "is_open": "1",
        "user_chat_id": "35ce7075c1c57bb6c66d0f67a7840383",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
        "id": "66",
        "add_time": "2019-12-17 11:15:35",
        "user_birthday": "1990-01-01",
        "user_email": "",
        "user_token": "633cae769e274cabd4441acb7be1c5a1"
      },
      {
        "login_name": "test14",
        "update_time": "2019-12-17 11:15:55",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "test14",
        "user_sex": "2",
        "user_mobile": "13980074654",
        "user_type": "2",
        "is_open": "1",
        "user_chat_id": "3190c55b297b51b38463da4eae6bbd95",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
        "id": "67",
        "add_time": "2019-12-17 11:15:55",
        "user_birthday": "1990-01-01",
        "user_email": "",
        "user_token": "84c5871da19f7a489234af73c491f74f"
      },
      {
        "login_name": "test15",
        "update_time": "2019-12-17 11:16:16",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "test15",
        "user_sex": "2",
        "user_mobile": "13980074655",
        "user_type": "2",
        "is_open": "1",
        "user_chat_id": "fd072f598ec1a978f5fb968dfa386f0d",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
        "id": "68",
        "add_time": "2019-12-17 11:16:16",
        "user_birthday": "1990-01-01",
        "user_email": "",
        "user_token": "5bb37b4045e9ad6eb1cc398d3170d33e"
      },
      {
        "login_name": "test16",
        "update_time": "2019-12-17 11:16:36",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "test16",
        "user_sex": "2",
        "user_mobile": "13980074656",
        "user_type": "2",
        "is_open": "1",
        "user_chat_id": "88178648656ae259bae213ee00ccb4c7",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
        "id": "69",
        "add_time": "2019-12-17 11:16:36",
        "user_birthday": "1990-01-01",
        "user_email": "",
        "user_token": "2926796eb8e990aa8bd726e121cb91e8"
      },
      {
        "login_name": "test17",
        "update_time": "2019-12-17 11:17:07",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "test17",
        "user_sex": "2",
        "user_mobile": "13980074653",
        "user_type": "2",
        "is_open": "1",
        "user_chat_id": "b03d6e7b4db061d52b3d420844a5dde8",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
        "id": "70",
        "add_time": "2019-12-17 11:17:07",
        "user_birthday": "1990-01-01",
        "user_email": "",
        "user_token": "bf028bc0353bf8ff070bfd62490ae284"
      },
      {
        "login_name": "test18",
        "update_time": "2019-12-17 11:17:25",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "test18",
        "user_sex": "2",
        "user_mobile": "13980074658",
        "user_type": "2",
        "is_open": "1",
        "user_chat_id": "c1eddd55f8efcec8da1e0cc6fc1a5624",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
        "id": "71",
        "add_time": "2019-12-17 11:17:25",
        "user_birthday": "1990-01-01",
        "user_email": "",
        "user_token": "4adbe2313b7e4967ac518e4e0a73f5c9"
      },
      {
        "login_name": "test19",
        "update_time": "2019-12-17 11:17:41",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "test19",
        "user_sex": "2",
        "user_mobile": "13980074659",
        "user_type": "2",
        "is_open": "1",
        "user_chat_id": "5bf1e9f7e4bf9aa2d8a633eddf628710",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
        "id": "72",
        "add_time": "2019-12-17 11:17:41",
        "user_birthday": "1990-01-01",
        "user_email": "",
        "user_token": "dd7ab3f1fb3e8651b35ba070d10594c7"
      },
      {
        "login_name": "15708495493",
        "update_time": "2020-03-02 14:31:36",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "clover",
        "user_sex": "2",
        "user_mobile": "15708495493",
        "user_type": "2",
        "is_open": "1",
        "user_chat_id": "251f91338781d5354e08c1351ca3342d",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
        "id": "166",
        "add_time": "2020-03-02 14:31:36",
        "user_birthday": "1990-01-01",
        "user_email": "",
        "user_token": "ff94d3f7b1dafada193ae7d6a82fa628"
      }
    ],
    "_links": {
      "self": {
        "href": "http://api.pcs-api.localhost/v1/cmc-users?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=efda7e64b7747f8c4360b29aa9c18f77&per-page=13&page=1"
      }
    },
    "_meta": {
      "totalCount": 13,
      "pageCount": 1,
      "currentPage": 1,
      "perPage": 13
    }
  }
}

10、在程序执行过程中,插入数据至 Redis 中时,会判断 ID 是否存在,存在则更新,不存在则插入。初步怀疑是在并发请求的情况下。皆执行了插入的操作。

            $redisCmcConsoleUser = new RedisCmcConsoleUser();
            $redisCmcConsoleUserResult = $redisCmcConsoleUser->initSync(['group_id' => $groupInfo['group_id']], $loginId, $loginTid);
            if ($redisCmcConsoleUserResult === false) {
                throw new NotFoundHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '201041'), ['id' => $loginId])), 201041);
            }

            $redisCmcConsoleUserItem = $redisCmcConsoleUser::find()->where(['id' => $userInfo['id'], 'group_id' => Yii::$app->params['groupId']])->one();

            /* 如果资源不存在,则插入;否则更新 */
            $redisCmcConsoleUserAttributes = [
                'id' => $userInfo['id'],
                'group_id' => $groupInfo['group_id'],
                'login_name' => $userInfo['login_name'],
                'user_token' => $userInfo['user_token'],
                'user_nick' => $userInfo['user_nick'],
                'user_pic' => $userInfo['user_pic'],
                'user_mobile' => $userInfo['user_mobile'] ? $userInfo['user_mobile'] : '',
                'user_email' => $userInfo['user_email'] ? $userInfo['user_email'] : '',
                'user_sex' => $userInfo['user_sex'],
                'user_type' => $userInfo['user_type'],
                'user_birthday' => $userInfo['user_birthday'],
                'user_chat_id' => $userInfo['user_chat_id'] ? $userInfo['user_chat_id'] : '',
                'is_open' => $userInfo['is_open'],
                'add_time' => $userInfo['add_time'],
                'update_time' => $userInfo['update_time'],
            ];
            if (!isset($redisCmcConsoleUserItem)) {
                $redisCmcConsoleUser->attributes = $redisCmcConsoleUserAttributes;
                $redisCmcConsoleUser->insert();
                // 设置用户身份为已认证
                Yii::$app->user->setIdentity($redisCmcConsoleUser);
            } else {
                $redisCmcConsoleUserItem->attributes = $redisCmcConsoleUserAttributes;
                $redisCmcConsoleUserItem->save();
                // 设置用户身份为已认证
                Yii::$app->user->setIdentity($redisCmcConsoleUserItem);
            }

11、在程序执行过程中,插入数据至 Redis 中时,不论 ID 是否存在,皆插入。请求接口,响应参数中资源总数量为 14 个。包含 id 等于 3 的资源是重复的。总计为 2 个。如图7

在程序执行过程中,插入数据至 Redis 中时,不论 ID 是否存在,皆插入。请求接口,响应参数中资源总数量为 14 个。包含 id 等于 3 的资源是重复的。总计为 2 个。

图7

            if (!isset($redisCmcConsoleUserItem)) {
                $redisCmcConsoleUser->attributes = $redisCmcConsoleUserAttributes;
                $redisCmcConsoleUser->insert();
                // 设置用户身份为已认证
                Yii::$app->user->setIdentity($redisCmcConsoleUser);
            } else {
                $redisCmcConsoleUserItem->attributes = $redisCmcConsoleUserAttributes;
                $redisCmcConsoleUserItem->insert();
                // 设置用户身份为已认证
                Yii::$app->user->setIdentity($redisCmcConsoleUserItem);
            }
{
  "code": 10000,
  "message": "获取 CMC 用户列表成功",
  "data": {
    "items": [
      {
        "login_name": "13281105967",
        "update_time": "2019-12-11 14:28:26",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "13281105967",
        "user_sex": "2",
        "user_mobile": "13281105967",
        "user_type": "1",
        "is_open": "1",
        "user_chat_id": "ede7616c5e4232896453202cd0c3f7ec",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/20190219/1550570817-4LLQJJ.png",
        "id": "3",
        "add_time": "2018-04-26 10:05:28",
        "user_birthday": "1990-01-01",
        "user_email": "13281105967@chinamcloud.com",
        "user_token": "fb46626f0e71e423ca8ab4c750620a85"
      },
      {
        "login_name": "13281105967",
        "update_time": "2019-12-11 14:28:26",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "13281105967",
        "user_sex": "2",
        "user_mobile": "13281105967",
        "user_type": "1",
        "is_open": "1",
        "user_chat_id": "ede7616c5e4232896453202cd0c3f7ec",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/20190219/1550570817-4LLQJJ.png",
        "id": "3",
        "add_time": "2018-04-26 10:05:28",
        "user_birthday": "1990-01-01",
        "user_email": "13281105967@chinamcloud.com",
        "user_token": "fb46626f0e71e423ca8ab4c750620a85"
      }
    ],
    "_links": {
      "self": {
        "href": "http://api.pcs-api.localhost/v1/cmc-users?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=efda7e64b7747f8c4360b29aa9c18f77&per-page=14&page=1"
      }
    },
    "_meta": {
      "totalCount": 14,
      "pageCount": 1,
      "currentPage": 1,
      "perPage": 14
    }
  }
}

12、由此可以确认,Redis ActiveRecord 不能够确保主键 ID 的唯一性的。现阶段有 2 种方案,第 1 种方案是插入记录时基于 Redis 实现唯一性的锁定。第 2 种方案是查询时去重。决定采用第 2 种方案。由于 redis 不支持 SQL 查询,因此查询 API 仅限于以下方法: where(),limit(),offset(),orderBy() 和 indexBy()。 (orderBy() 尚未实现:#1305)。基于 indexBy()。请求接口,响应参数中资源总数量为 13 个。ID 主键未重复。但是,totalCount 的值为 14。统计错误。如图8

由此可以确认,Redis ActiveRecord 不能够确保主键 ID 的唯一性的。现阶段有 2 种方案,第 1 种方案是插入记录时基于 Redis 实现唯一性的锁定。第 2 种方案是查询时去重。决定采用第 2 种方案。由于 redis 不支持 SQL 查询,因此查询 API 仅限于以下方法: where(),limit(),offset(),orderBy() 和 indexBy()。 (orderBy() 尚未实现:#1305)。基于 indexBy()。请求接口,响应参数中资源总数量为 13 个。ID 主键未重复。但是,totalCount 的值为 14。统计错误。

图8

        // 查询当前用户所属租户 ID 下的 CMC 的用户模型(Redis)
        $query = $modelClass::find()
            ->where([
                'group_id' => $identity->group_id,
                'is_open' => $modelClass::STATUS_ENABLED
            ])
            ->indexBy('id');
{
  "code": 10000,
  "message": "获取 CMC 用户列表成功",
  "data": {
    "items": [
      {
        "login_name": "13281105967",
        "update_time": "2019-12-11 14:28:26",
        "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
        "user_nick": "13281105967",
        "user_sex": "2",
        "user_mobile": "13281105967",
        "user_type": "1",
        "is_open": "1",
        "user_chat_id": "ede7616c5e4232896453202cd0c3f7ec",
        "user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/20190219/1550570817-4LLQJJ.png",
        "id": "3",
        "add_time": "2018-04-26 10:05:28",
        "user_birthday": "1990-01-01",
        "user_email": "13281105967@chinamcloud.com",
        "user_token": "fb46626f0e71e423ca8ab4c750620a85"
      }
    ],
    "_links": {
      "self": {
        "href": "http://api.pcs-api.localhost/v1/cmc-users?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=efda7e64b7747f8c4360b29aa9c18f77&per-page=14&page=1"
      }
    },
    "_meta": {
      "totalCount": 14,
      "pageCount": 1,
      "currentPage": 1,
      "perPage": 14
    }
  }
}

13、因此,尝试采用第 1 种方案。不过由于 此处程序实现 是所有请求皆会执行到的流程,担心锁定实现降低程序性能,最终决定,放弃插入,仅做更新。如果 Redis 中用户不存在,则插入;否则更新。调整为:如果 Redis 中用户不存在,则响应 404;否则更新。

            /* 如果资源不存在,则响应 404 */
            if (!isset($redisCmcConsoleUserItem)) {
                throw new NotFoundHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '201011'), ['user_nick' => $userInfo['user_nick']])), 201011);
            }

            /* 更新 */
            $redisCmcConsoleUserItem->attributes = $redisCmcConsoleUserAttributes;
            $redisCmcConsoleUserItem->save();
            // 设置用户身份为已认证
            Yii::$app->user->setIdentity($redisCmcConsoleUserItem);

14、如果 Redis 中用户不存在,则响应 404。如图9

如果 Redis 中用户不存在,则响应 404。

图9

15、但是,此修复仅防止以后出现用户重复的问题,之前已经重复的用户,仍然是重复的。如果要去重,需要手动操作 Redis。且此修复会衍生出一个新的影响体验的问题,即在框架处新添加了一个用户 B 后,如果用户 B 在 Redis 中不存在,则用户 B 无法使用策划指挥。需要等待用户 B 同步至 Redis 后,才可使用。

 

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/250529.html

(0)
上一篇 2022年4月29日 23:40
下一篇 2022年4月29日 23:40

相关推荐

发表回复

登录后才能评论