H5活動抽獎

zhou發表於2019-02-16

本文講解內容

針對兩類發獎需求的四種抽獎邏輯及細節

一般H5抽獎活動的發獎需求分為

1.一定中獎(獎品庫存不空的情況下)
2.不一定中獎

發獎介面的最終實現要求

1.獎品不超發
2.唯一獎品單次發放
3.對併發有一定的限制

介面實戰

1.根據獎品開放時間進行抽獎

public function award($openid)
    {
        $award = Award::find()->where([`openid` => ``])
            ->andWhere([`>`, `open_at`, 0])->andWhere([`<`, `open_at`, time()])
            ->orderBy(`open_at ASC`)->limit(1)->one();
        if (!empty($award)) {
            $res = Award::updateAll(
                [
                    `openid` => $openid
                ],
                `code = :code AND openid = :openid`,
                [
                    `:code` => $award[`code`],
                    `:openid` => ``
                ]
            );
            if ($res) {
                return ArrayHelper::toArray($award);
            }
        }
        return [];
    }

這種方式,多使用者併發情況下,會出現多個使用者相同獎品,由於update語句限制,拿到相同獎品碼的使用者中只有一人能中得獎品。

2.在開放時間的基礎上加上型別概率

public function randAward($openid)
    {
        $number = rand(0, 100);
        $type = 5;
        if ($number < 10) {
            $type = 1;
        } else if ($number < 30) {
            $type = 2;
        } else if ($number < 70) {
            $type = 3;
        } else if ($number < 80) {
            $type = 4;
        }
        $award = Award::find()->where([`openid` => ``])
            ->andWhere([`>`, `open_at`, 0])->andWhere([`<`, `open_at`, time()])
            ->andWhere([`type` => $type])
            ->orderBy(`open_at ASC`)->limit(1)->one();
        if (!empty($award)) {
            $res = Award::updateAll(
                [
                    `openid` => $openid
                ],
                `code = :code AND openid = :openid`,
                [
                    `:code` => $award[`code`],
                    `:openid` => ``
                ]
            );
            if ($res) {
                return ArrayHelper::toArray($award);
            }
        }
        return [];
    }

這種方式,也會出現多個使用者相同獎品,但加上type限制後,使用者被分散在各個型別中,未中獎概率會比上面的例子低。

3.利用Redis獎品池的概念進行發獎

    public function redisAward($openid)
    {
        try {
            $redis = Yii::$app->redis->client();
            $code = $redis->LPop(self::AWARD_LIST_KEY);
        } catch (Exception $err) {
            return [];
        }
        $res = Award::updateAll(
            [
                `openid` => $openid
            ],
            `code = :code AND openid = :openid`,
            [
                `:code` => $code,
                `:openid` => ``
            ]
        );
        if ($res) {
            $award = Award::find()->where([`code` => $code])->limit(1)->one();
            return ArrayHelper::toArray($award);
        }
        return [];
    }

這種利用預先生成獎品池的方式,獎品池不空的情況下,每個使用者都會取走不同獎品碼,要注意的是 前期生成獎品池及後期操作獎品池時,防止獎品碼複用

4.根據獎品開放時間(型別)進行抽獎,換成用sql語句進行發獎

public function sqlAward($openid)
    {
        $sql = "UPDATE award SET openid = :openid 
                WHERE open_at > 0 AND openid = `` AND open_at < :time
                ORDER BY open_at ASC LIMIT 1";
        $res = Yii::$app->db->createCommand($sql, [`:time` => time(), `:openid` => $openid])->execute();
        if ($res) {
            return Award::find()->where([`openid` => $openid])->limit(1)->asArray()->one();
        }
        return [];
    }

一定中獎需求下,建議採用Redis獎品池或者sql語句進行update
以上四種方式在多使用者併發的情況下帶來不一樣的結果

除了多使用者併發,還會出現惡刷情況,就是同一使用者併發請求
這種情況應該在真正進入抽獎邏輯之前進行限制

可以根據實際需求搭配以下方式進行限制

public function actionAward()
    {
        $openid = `okjkLj7-UL4gXknY9bDkFn0O6Jos`;
        $redis = Yii::$app->redis->client();
//            使用者單次數
        if (!$redis->sAdd(self::USER_LIST_KEY, $openid)) {
            return [];
        }
        return $this->sqlAward($openid);
    }

也可以限制抽獎人數

public function actionAward()
    {
        $openid = CommonTool::randString(32);
        try {
            $redis = Yii::$app->redis->client();
//            抽獎使用者數量
            $list = $redis->sMembers(self::USER_LIST_KEY);
            if (count($list) > 1000) {
                return ;
            }
        } catch (Exception $err) {

        }
        $award = $this->sqlAward($openid);
    }

寫在最後的最後

H5活動抽獎介面需要注意幾點
1.檢查使用者有效性
2.限制單使用者訪問次數
3.使用概率讓使用者分流,從而控制真正進入抽獎邏輯的請求
4.記錄抽獎領獎等相關操作的時間裝置IP等..
5.控制獎品的分佈(時間,插空,概率等)
6.做好索引關係

相關文章