ThinkPHP5:评论、回复功能设计,连表查询优化

目录

0x00 评论表设计

0x01 控制器

0x02 Model层

0x03 关联查询优化

连表查询的劣势:

优化思路:(多次单表查询+拼接数据)

代码:


0x00 评论表设计

0x01 控制器

<?php
/*
 * @Author: your name
 * @Date: 2020-07-18 23:48:49
 * @LastEditTime: 2020-07-19 11:29:59
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /myNewsApp/application/api/controller/v1/Comment.php
 */

namespace app\api\controller\v1;

use app\api\controller\v1\AuthBase;
use think\Log;

class Comment extends AuthBase
{
    /**
     * @description: 评论回复功能开发
     * @method POST
     * @param {type} 
     * @return: 
     */
    public function save()
    {
        $data = input('post.', [], 'htmlspecialchars');
        //后端效验
        $cmt_validate = validate('CmtValidate');
        if (!$cmt_validate->check($data)) {
            return show(config('api.fail_code'), $cmt_validate->getError(), [], 403);
        }
        //查询数据库中是否有该文章
        if (!model('News')->where(['id' => $data['news_id']])->find()) {
            return show(config('api.fail_code'), "文章不存在", [], 404);
        }
        $data['user_id'] = $this->user->id;
        try {
            $commentId = model('Comment')->add($data);
            //回写
            if ($commentId && model('News')->where(['id' => $data['news_id']])->setInc('comment_count')) {
                return show(config('api.success_code'), '评论成功!', [], 202);
            } else {
                return show(config('api.fali_code'), '评论失败!', [], 500);
            }
        } catch (\Exception $e) {
            Log::write($e->getMessage());
            return show('api.fali_code', '评论失败!', [], 500);
        }
    }
    /**
     * @description: 评论列表API v1.0
     * @method GET
     * @param {type} 
     * @return: 
     */
    // public function read(){
    //     $news_id = input('param.id',0,'intval');
    //     if(empty($news_id)){
    //         return show(config('api.fail_code'),'请输入文章id',[],404);
    //     }
    //     $param['news_id']= $news_id;
    //     $count = model('Comment')->getNormalCommentsCountByCondition($param);
    //     $ret = model('Comment')->getNormalCommentsByCondition($param,0,20);
    //     if($ret){
    //         $result = [
    //             'total'=>$count,
    //             'list'=>$ret
    //         ];
    //         return show(config('api.success_code'),'获取评论成功!',$result,200);
    //     }else{
    //         return show(config('api.fail_code'),'获取评论失败!',[],500);
    //     }
    // }

    /**
     * @description:评论列表API v2.0
     * @method GET 
     * @param {type} 
     * @return: 
     */
    public function read()
    {
        $news_id = input('param.id', 0, 'intval');
        if (empty($news_id)) {
            return show(config('api.fail_code'), '请输入文章id', [], 404);
        }
        $param['news_id'] = $news_id;
        $count = model('Comment')->getCountByCondition($param);
        $comments = model('Comment')->getListsByCondition($param,0,20);
        if($comments){
            foreach($comments as $comment){
                $userIds[]=$comment['user_id'];
                if($comment['to_user_id']){
                    $userIds[] = $comment['to_user_id'];
                }
            }
            $userIds = array_unique($userIds);
        }
        $userIds = model('User')->getUsersByUserId($userIds);
        if(empty($userIds)){
            $userIdNames = [];
        }else{
            foreach($userIds as $userId){
                $userIdNames[$userId->id] = $userId;
            }
        }
        foreach($comments as $comment){
            $resultDatas[] = [
                'id'=>$comment->id,
                'user_id'=>$comment->user_id,
                'to_user_id'=>$comment->to_user_id,
                'content' => $comment->content,
                'username'=>!empty($userIdNames[$comment->user_id])?$userIdNames[$comment->user_id]->username:'',
                'tousername'=>!empty($userIdNames[$comment->to_user_id])?$userIdNames[$comment->to_user_id]->username:'',
                'username_image'=>!empty($userIdNames[$comment->user_id])?$userIdNames[$comment->user_id]->image:'',
                'tousername_image'=>!empty($userIdNames[$comment->to_user_id])?$userIdNames[$comment->to_user_id]->image:'',
                'create_time'=>$comment->create_time
            ];
        }
        return show(config('api.success_code'),'获取用户列表成功!',$resultDatas,200);
    }


}

0x02 Model层

<?php
/*
 * @Author: your name
 * @Date: 2020-07-18 23:53:25
 * @LastEditTime: 2020-07-19 10:28:35
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /myNewsApp/application/common/model/Comment.php
 */ 
namespace app\common\model;
use app\common\model\Base;

class Comment extends Base{
    /**
     * @description: 通过条件获取评论的数量
     * @param {type} 
     * @return: 
     */    
    public function getNormalCommentsCountByCondition($param = []){
        $count = $this
        ->alias('c')
        // ->join('ent_user u','c.user_id = u.id')
        ->where(['c.news_id'=>$param['news_id']])
        ->count();
        return $count;
    }
    /**
     * @description: 通过条件获取列表数据
     * @param {type} 
     * @return: 
     */    
    public function getNormalCommentsByCondition($param=[],$from=0,$size=5){
        $ret = $this
        ->alias('c')
        ->join('ent_user u','c.user_id = u.id')
        ->where(['c.news_id'=>$param['news_id']])
        ->limit($from,$size)
        ->order(['c.create_time'=>'DESC'])
        ->select();

        return $ret;
    }
    public function getCountByCondition($param=[]){
        return $this->where($param)
        ->field('id')
        ->count();
    }


    /**
     * @description: 获取评论列表
     * @param {type} 
     * @return: 
     */    
    public function getListsByCondition($param=[],$from=0,$size=5){
        return $this->where($param)
                    ->field('*')
                    ->limit($from,$size)
                    ->order(['create_time'=>'desc'])
                    ->select();
    }
}

0x03 关联查询优化

连表查询的劣势:

1.多个表同时读会导致多个表同时被锁,多个表不能写入。 并且这种锁机制会拉慢性能,导致连表查询 比 同样的多次单表查询慢很多。

2大量的关联查询会导致集中式的数据库架构很难向分布式架构转换

优化思路:(多次单表查询+拼接数据)

先将主表信息查询出来,

然后将userid toUserId 弄成一个数组 去重

然后用这个数组 去 副表中查 对应的信息(in)

以id为键,组成一个数组

然后将两个数组 中有用的信息拼成一个数组返回

代码:

    /**
     * @description:评论列表API v2.0
     * @method GET 
     * @param {type} 
     * @return: 
     */
    public function read()
    {
        $news_id = input('param.id', 0, 'intval');
        if (empty($news_id)) {
            return show(config('api.fail_code'), '请输入文章id', [], 404);
        }
        $param['news_id'] = $news_id;
        $count = model('Comment')->getCountByCondition($param);
        $comments = model('Comment')->getListsByCondition($param,0,20);
        if($comments){
            foreach($comments as $comment){
                $userIds[]=$comment['user_id'];
                if($comment['to_user_id']){
                    $userIds[] = $comment['to_user_id'];
                }
            }
            $userIds = array_unique($userIds);
        }
        $userIds = model('User')->getUsersByUserId($userIds);
        if(empty($userIds)){
            $userIdNames = [];
        }else{
            foreach($userIds as $userId){
                $userIdNames[$userId->id] = $userId;
            }
        }
        foreach($comments as $comment){
            $resultDatas[] = [
                'id'=>$comment->id,
                'user_id'=>$comment->user_id,
                'to_user_id'=>$comment->to_user_id,
                'content' => $comment->content,
                'username'=>!empty($userIdNames[$comment->user_id])?$userIdNames[$comment->user_id]->username:'',
                'tousername'=>!empty($userIdNames[$comment->to_user_id])?$userIdNames[$comment->to_user_id]->username:'',
                'username_image'=>!empty($userIdNames[$comment->user_id])?$userIdNames[$comment->user_id]->image:'',
                'tousername_image'=>!empty($userIdNames[$comment->to_user_id])?$userIdNames[$comment->to_user_id]->image:'',
                'create_time'=>$comment->create_time
            ];
        }
        return show(config('api.success_code'),'获取用户列表成功!',$resultDatas,200);
    }

User表:

<?php
/*
 * @Author: your name
 * @Date: 2020-07-17 13:26:11
 * @LastEditTime: 2020-07-19 10:59:58
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /myNewsApp/application/common/model/User.php
 */ 
namespace app\common\model;
use think\model;

class User extends Model{
    protected $autoWriteTimestamp = true;

    public function getUsersByUserId($userIds=[]){
        $data  = [
            'id'=>['in',implode(',',$userIds)]
        ];
        $order = [
            'create_time'=>'DESC'
        ];
        return $this->field(['id','username','image'])
                    ->where($data)
                    ->order($order)
                    ->select();
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值