嵌套集合示例

嵌套集合插入

// 注册
    public function register(Request $request)
    {
        try{
            $post = $request->param();
            $this->validate($post,Register::class);
            //验证短信验证码
            if (!checkSms($post['phone'], 'register', $post['code'])) {
                return resjson(400, '短信验证码输入错误');
            }
        }catch (ValidateException $e){
            return resjson(400, $e->getError());
        }


        $servers = [
            ['127.0.0.1', 6379, 0.01],
        ];
        $redLock = new \RedLock($servers);

        //加锁
        $lock = $redLock->lock('set_user_lft_and_rgt', 2000);

        Db::startTrans();
        try {
            $userModel = new \app\model\User();
            $userModel->salt = rand(1000, 9999);
            $userModel->password = system_encrypt($post['password'], $userModel->salt);
            $userModel->username = $post['phone'];
            $userModel->phone = $post['phone'];
            $userModel->nickname = '用户' . substr($post['phone'], 7);
            $userModel->account = getUniqueNum(new \app\model\User(), 'account', 8);
            $userModel->source = $request->header('apptype') || '';
            //默认服务商节点ID为1
            $userModel->store_id = 1;
            //默认邀请人
            //$userModel->pid = Store::where('id',$userModel->store_id)->value('user_id') ?? 0;
            $userModel->pid = config('base.default_pid') ?? 0;

            $userModel->depth = 3;

            //获取推荐人
            //$super = new \app\model\User();
            if (!empty($post['account'])) {
                $super = \app\model\User::where('account',$post['account'])->findOrEmpty();
                if(!$super->isEmpty()){
                    $userModel->pid = $super->id;
                    $super->inviter_num = Db::raw('inviter_num+1');
                    //继承上级节点
                    $userModel->store_id = $super->store_id;
                    $userModel->depth = $super->depth + 1;
                    //判断是否是叶子节点
                    if($super['rgt'] == $super['lft'] + 1){
                        $rgt = $super['lft'];
                    }else{
                        //不是叶子节点,获取位置
                        $rgt = Db::name('user')->where('pid','=',$super->id)->order('rgt','desc')->value('rgt');
                    }
                }/*else{
                    $rgt = Db::name('user')->where('pid','=',$userModel->pid)->order('rgt','desc')->lock(true)->value('rgt');
                }*/
            }/*else{
                $rgt = Db::name('user')->where('pid','=',$userModel->pid)->order('rgt','desc')->lock(true)->value('rgt');
            }*/

            if(!isset($super) || $super->isEmpty()){
                $super = \app\model\User::where('id',$userModel->pid)->findOrEmpty();
                //判断是否是叶子节点
                if($super['rgt'] == $super['lft'] + 1){
                    $rgt = $super['lft'];
                }else{
                    //不是叶子节点,获取位置
                    $rgt = Db::name('user')->where('pid','=',$super->id)->order('rgt','desc')->value('rgt');
                }
            }
            Db::name('user')->where('rgt','>',$rgt)->order('rgt','desc')->inc('rgt',2)->update();
            Db::name('user')->where('lft','>',$rgt)->order('lft','desc')->inc('lft',2)->update();
            $userModel->lft = $rgt + 1;
            $userModel->rgt = $rgt + 2;
            $userModel->origin_pid = $userModel->pid;
            $userModel->store_id = $super->store_id;
            $userModel->depth = $super['depth'] + 1;
            if(!$userModel->save()){
                throw new \Exception('注册失败',400);
            }

            // 触发UserRegister事件
            $bonus = new Bonus();
            $bonus->type = Bonus::REGISTER;
            Event::trigger(new UserRegister($userModel,$super,$bonus));
            $userModel->save();
            if(isset($super->id)){
                $super->save();
            }
            Db::commit();

            //删除锁
            $redLock->unlock($lock);

            //重新登录
            $user = new \app\model\User();
            $user = $user->where('id',$userModel->id)
//                ->field('id,username,account,phone,nickname,sex,email,headimg,status')
//                ->withoutField('salt,password,deal_pwd')
                ->find();
            if (!$user) {
                return resjson(404, '注册失败');
            }
            $user->append(['store_text','is_deal_pwd']);
            $user->token = setToken($user->phone);
            $userArr = $user->toArray();

            //更新登录信息
            $user->last_login = date('Y-m-d H:i:s', time());
            $user->last_ip = $this->request->ip();
            $user->save();
            Cache::set($user->token, $user, config('common.expires'));

            unset($userArr['password']);
            unset($userArr['salt']);
            unset($userArr['deal_pwd']);


        } catch (\Exception $exception) {
            Db::rollback();
            //删除锁
            $redLock->unlock($lock);
            if($exception->getCode() == 400){
                return resjson(400, $exception->getMessage());
            }
            return resjson(500, '服务器错误');
        }
        return resjson(200, '注册成功',$userArr);

    }

修改节点

//设置节点归属
    public function setStore($id,$pid,$store_id = 0)
    {
        $user = \app\model\User::findOrEmpty($id);
        if($pid){
            $newParentUser = \app\model\User::findOrEmpty($pid);
            if(!$newParentUser){
                $this->error = '上级用户不存在';
                return false;
            }
        }else{
            //顶级栏目
            if($store_id <= 0){
                $this->error = '调整为顶级用户必须关联节点';
                return false;
            }
        }

        $servers = [
            ['127.0.0.1', 6379, 0.01],
        ];
        $redLock = new \RedLock($servers);

        //加锁
        $lock = $redLock->lock('set_user_lft_and_rgt', 5000);

        //将节点及其所有子节点的位置更改为负值,该值等于模块中的当前值。
        //将所有位置“向上”移动,更多,即当前节点的pos_right。
        //将所有位置“向下”移动更多,即新父节点的pos_right。
        //更改当前节点及其所有子节点的位置,以使它现在恰好在新父节点的“之后”(或“向下”)。

        // 启动事务
        Db::startTrans();
        try {
            //1.将节点及其所有子节点的位置更改为负值,该值等于模块中的当前值。
            \app\model\User::where('lft','>=',$user['lft'])->where('rgt','<=',$user['rgt'])->update([
                'lft'=>Db::raw('0-lft'),
                'rgt'=>Db::raw('0-rgt'),
            ]);
            //2.将所有位置“向上”移动,(当前用户右边的用户左移)
            $size = $user['rgt'] - $user['lft'] + 1;
            \app\model\User::where('lft','>',$user['rgt'])->dec('lft',$size)->update();
            \app\model\User::where('rgt','>',$user['rgt'])->dec('rgt',$size)->update();

            if($pid){
                //3.将所有位置“向下”移动,(新父级用户右边的用户右移)
                $newSize = $newParentUser['rgt'] > $user['rgt'] ? $newParentUser['rgt'] - $size : $newParentUser['rgt'];
                \app\model\User::where('lft','>=',$newSize)->inc('lft',$size)->update();
                \app\model\User::where('rgt','>=',$newSize)->inc('rgt',$size)->update();
                //4.更改当前节点及其所有子节点的位置
                $addSize = $newParentUser['rgt'] > $user['rgt'] ? $newParentUser['rgt'] - $user['rgt'] - 1 : $newParentUser['rgt'] - $user['rgt'] - 1 + $size;
                \app\model\User::where('lft','<=',0-$user['lft'])->where('rgt','>=',0-$user['rgt'])->update([
                    'lft'=>Db::raw('0-lft+'.$addSize),
                    'rgt'=>Db::raw('0-rgt+'.$addSize)
                ]);
                //5.修改用户节点,上级
                \app\model\User::where('id',$user['id'])->update([
                    'pid'=>$newParentUser['id'],
                    'old_pid'=>$user['pid'],
                    'store_id'=>$newParentUser['store_id'],
                ]);
                //6.修改下级用户节点归属
                $newUser = \app\model\User::where('id',$user['id'])->find();
                \app\model\User::where('lft','>',$newUser['lft'])->where('rgt','<',$newUser['rgt'])->update(['store_id'=>$newParentUser['store_id']]);
                //7.修改用户节点深度
                $depth = $newParentUser['depth'] + 1 - $newUser['depth'];
                if($depth != 0){
                    \app\model\User::where('lft','>=',$newUser['lft'])->where('rgt','<=',$newUser['rgt'])->inc('depth',$depth)->update();
                }
            }else{
                //顶级用户

                //4.更改当前节点及其所有子节点的位置
                $topRight = \app\model\User::order('rgt','desc')->find();
                $addSize = $topRight['rgt'] + 1 - $user['lft'];
                \app\model\User::where('lft','<=',0-$user['lft'])->where('rgt','>=',0-$user['rgt'])->update([
                    'lft'=>Db::raw('0-lft+'.$addSize),
                    'rgt'=>Db::raw('0-rgt+'.$addSize)
                ]);
                //5.修改用户节点,上级
                \app\model\User::where('id',$user['id'])->update([
                    'pid'=>0,
                    'old_pid'=>$user['pid'],
                    'store_id'=>$store_id,
                ]);
                //6.修改下级用户节点归属
                $newUser = \app\model\User::where('id',$user['id'])->find();
                \app\model\User::where('lft','>',$newUser['lft'])->where('rgt','<',$newUser['rgt'])->update(['store_id'=>$store_id]);
                //7.修改用户节点深度
                $depth = 1 - $newUser['depth'];
                if($depth != 0){
                    \app\model\User::where('lft','>=',$newUser['lft'])->where('rgt','<=',$newUser['rgt'])->inc('depth',$depth)->update();
                }
            }
            // 提交事务
            Db::commit();
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
            $this->error = '操作失败';
            return false;
        }

        //删除锁
        $redLock->unlock($lock);

        //记录日志
        Db::name('store_log')->insert([
            'user_id'=>$id,
            'pid'=>$newUser->pid,
            'store_id'=>$newUser->store_id,
            'create_time'=>time(),
            'update_time'=>time(),
            'description'=>request()->param('description',''),
            'action_id'=>app('loginUser')->user_id,
            'before_id'=>$user->pid,
            'before_store_id'=>$user->store_id,
        ]);

        return true;
    }

redis分布式锁实现代码

<?php


class RedLock
{
    private $retryDelay;
    private $retryCount;
    private $clockDriftFactor = 0.01;

    private $quorum;

    private $servers = array();
    private $instances = array();

    function __construct(array $servers, $retryDelay = 200, $retryCount = 3)
    {
        $this->servers = $servers;

        $this->retryDelay = $retryDelay;
        $this->retryCount = $retryCount;

        $this->quorum  = min(count($servers), (count($servers) / 2 + 1));
    }

    public function lock($resource, $ttl)
    {
        $this->initInstances();

        $token = uniqid();
        $retry = $this->retryCount;

        do {
            $n = 0;

            $startTime = microtime(true) * 1000;

            foreach ($this->instances as $instance) {
                if ($this->lockInstance($instance, $resource, $token, $ttl)) {
                    $n++;
                }
            }

            # Add 2 milliseconds to the drift to account for Redis expires
            # precision, which is 1 millisecond, plus 1 millisecond min drift
            # for small TTLs.
            $drift = ($ttl * $this->clockDriftFactor) + 2;

            $validityTime = $ttl - (microtime(true) * 1000 - $startTime) - $drift;

            if ($n >= $this->quorum && $validityTime > 0) {
                return [
                    'validity' => $validityTime,
                    'resource' => $resource,
                    'token'    => $token,
                ];

            } else {
                foreach ($this->instances as $instance) {
                    $this->unlockInstance($instance, $resource, $token);
                }
            }

            // Wait a random delay before to retry
            $delay = mt_rand(floor($this->retryDelay / 2), $this->retryDelay);
            usleep($delay * 1000);

            $retry--;

        } while ($retry > 0);

        return false;
    }

    public function unlock(array $lock)
    {
        $this->initInstances();
        $resource = $lock['resource'];
        $token    = $lock['token'];

        foreach ($this->instances as $instance) {
            $this->unlockInstance($instance, $resource, $token);
        }
    }

    private function initInstances()
    {
        if (empty($this->instances)) {
            foreach ($this->servers as $server) {
                list($host, $port, $timeout) = $server;
                $redis = new \Redis();
                $redis->connect($host, $port, $timeout);

                $this->instances[] = $redis;
            }
        }
    }

    private function lockInstance($instance, $resource, $token, $ttl)
    {
        return $instance->set($resource, $token, ['NX', 'PX' => $ttl]);
    }

    private function unlockInstance($instance, $resource, $token)
    {
        $script = '
            if redis.call("GET", KEYS[1]) == ARGV[1] then
                return redis.call("DEL", KEYS[1])
            else
                return 0
            end
        ';
        return $instance->eval($script, [$resource, $token], 1);
    }
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇