Laravel 实现 Mysql 用户表分表及查询

前情提要

这是一个使用 Laravel 实现的分表场景。

通常一个应用拥有了一定量级用户的时候,应用方都会自建自己的用户认证服务,无论使用何种实现方式,在这里我统称为 Passport Server ,其目的都是为了验证用户、保存维护用户、为成员网站提供当前用户的信息状态。

这时,我如果是作为其中的一个成员网站(比如统一的用户中心),在用户注册/登录访问时,就会将用户的登录表单信息提交给 Passport Server ,当 Passport Server 验证通过后会向我返回该用户的基本信息,随即我会根据这些信息或创建,或查找该用户在本系统的记录,以便提供本系统的各项服务。

随着成员网站的增多(可想象为一个大型游戏公司,注册一个账号,在旗下多款游戏可以通用),用户的数量的剧增,我这个成员网站作为一个重要的节点,所有用户都会过来进行操作,这时我就要考虑将这些巨量的用户数据通过拆表的方式进行处理。

注册/登录场景

在统一的注册页面有三种注册方式,手机号码注册、邮箱注册、自定义通行证注册,在这三种不同的注册方式内,根据相关要求,手机号码这个字段均存在且必填及短信验证。当用户注册完成后,将用户的注册信息提交给 Passport Server

在统一的登录页面,用户可根据手机号码、邮箱(可以后绑定)、自定义的通行证进行登录操作,当用户提交登录表单时,将用户的登录信息提交给 Passport Server 后返回相应信息,跳转回目标站点。

实现拆表
拆表的散列算法

该算法根据自身应用可自行选择,这里会根据登录成功 Passport Server 返回的共通字段(因为三种注册方式都必填手机号码)进行散列分表,算法如下

// 这个算法,会生成32张表,如:users_a7、users_70
function getPrefix($account)
    {
        $passport = strtolower($account);
        $key = md5($passport);
        $key_1 = $key [3];
        $key_2 = $key [9];
        if ($key_2 >= '7') {
            $key_2 = 7;
        } else {
            $key_2 = 0;
        }

        return $key_1.$key_2;
    }
改造 Laravel 的 User Model
<?php

namespace App\Models;

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Eloquent\Model as EloquentModel;

class User extends EloquentModel
{
    protected $fillable = [ 'username', 'email', 'password', 'mobile'];
    
    public function __construct(array $attributes = [])
    {
        if (isset($attributes['mobile'])) {
            $this->setTableByAccount($attributes['mobile']);
        }
        parent::__construct($attributes);
    }
    
    // 动态指定数据表
    public function setTableByMobile($mobile)
    {
        $tb = 'users_'.$this->getPrefix($account);
		
        // 可以用其他方式实现该步骤,查询表,不存在则创建
        if(!Schema::hasTable($tb)){
            Schema::create($tb, function ($table) {
                $table->id('int', 11);
                $table->string('username', 30);
                $table->string('email', 30)->unique();
                $table->string('mobile', 30)->unique();
                $table->string('password', 32);
                $table->timestamps();
                $table->timestamp('deleted_at')->nullable();
            });
        }
        
        $this->setTable($tb);
    }
    
    // 传递给构造函数根据哪个字段查找表
    public static function selectTableByMobile($mobile)
    {
        return new static(['mobile' => $mobile]);
    }
}
控制器内使用
<?php
namespace App\Http\Controllers;

use App\Models\User;

class UserController extends Controller
{
    public function test()
    {
        $mobile = '13800138000';
        $email = 'xxx@qq.com';
        
        $user = User::selectTableByMobile($mobile)->where('email', $email)->first();

        dd($user->toArray());
    }
}
结论

上面所实现的拆表方式经过测试正常运行,如果没有上面我所说的 Passport Server 服务,在单一应用中只需要有适合自己业务的哈希分表算法,上述代码均可借鉴。

在查找表的过程中如果没有该表则创建的逻辑,可以使用中间件等其他方式实现,这里仅举例一种方式,并非唯一。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吹落的树叶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值