做小程序红包用户领取红包后如何防止重复领取

做小程序红包功能为了防止用户重复领取红包,确保系统的稳定性和公平性。可以采取以下措施:

1. 数据库唯一性约束

在数据库中为红包领取记录设置唯一性约束,确保每个用户只能领取一次红包。

CREATE TABLE red_packet_records (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    red_packet_id INT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY unique_user_red_packet (user_id, red_packet_id)
);

2. 领取前检查

在用户领取红包前,先检查数据库中是否已有该用户的领取记录。

// 检查用户是否已领取红包
$hasReceived = Db::table('red_packet_records')
    ->where('user_id', $userId)
    ->where('red_packet_id', $redPacketId)
    ->count();

if ($hasReceived > 0) {
    // 用户已领取红包
    return ['status' => 'error', 'message' => '您已经领取过该红包'];
} else {
    // 用户未领取红包,可以进行领取操作
    $result = Db::table('red_packet_records')->insert([
        'user_id' => $userId,
        'red_packet_id' => $redPacketId
    ]);

    if ($result) {
        // 领取成功
        return ['status' => 'success', 'message' => '红包领取成功'];
    } else {
        // 领取失败
        return ['status' => 'error', 'message' => '红包领取失败'];
    }
}

3. 分布式锁

在高并发场景下,可以使用分布式锁来确保同一时间只有一个请求能够处理用户的领取操作。

// 使用Redis实现分布式锁
$lockKey = 'lock:red_packet:' . $userId . ':' . $redPacketId;
$lockValue = uniqid();
$lockExpire = 10; // 锁的过期时间,单位秒

$result = Redis::setnx($lockKey, $lockValue);
if ($result === 1) {
    Redis::expire($lockKey, $lockExpire);

    // 检查用户是否已领取红包
    $hasReceived = Db::table('red_packet_records')
        ->where('user_id', $userId)
        ->where('red_packet_id', $redPacketId)
        ->count();

    if ($hasReceived > 0) {
        // 用户已领取红包
        Redis::del($lockKey);
        return ['status' => 'error', 'message' => '您已经领取过该红包'];
    } else {
        // 用户未领取红包,可以进行领取操作
        $result = Db::table('red_packet_records')->insert([
            'user_id' => $userId,
            'red_packet_id' => $redPacketId
        ]);

        if ($result) {
            // 领取成功
            Redis::del($lockKey);
            return ['status' => 'success', 'message' => '红包领取成功'];
        } else {
            // 领取失败
            Redis::del($lockKey);
            return ['status' => 'error', 'message' => '红包领取失败'];
        }
    }
} else {
    // 获取锁失败,稍后重试
    return ['status' => 'error', 'message' => '系统繁忙,请稍后重试'];
}

4. 前端防重复点击

在前端页面上,可以通过禁用按钮等方式防止用户重复点击领取按钮。

// 领取红包按钮点击事件
$('#receive-btn').on('click', function() {
    var $btn = $(this);
    $btn.prop('disabled', true); // 禁用按钮

    $.ajax({
        url: '/api/receiveRedPacket',
        method: 'POST',
        data: {
            userId: $userId,
            redPacketId: $redPacketId
        },
        success: function(response) {
            if (response.status === 'success') {
                alert('红包领取成功');
            } else {
                alert(response.message);
            }
        },
        complete: function() {
            $btn.prop('disabled', false); // 启用按钮
        }
    });
});

通过以上措施,可以有效防止用户重复领取红包,确保系统的稳定性和公平性。

0 条评论

还没有人发表评论

发表评论 取消回复

记住我的信息,方便下次评论
有人回复时邮件通知我