php+redis+mysql关注的实现

php+redis+mysql关注的实现

这个博客系统的项目我放在gitee上面,目前我还在开发中,我将地址放到下面

https://gitee.com/wyqgg/iblog

使用git克隆项目
git clone https://gitee.com/wyqgg/iblog.git

1、使用zadd向我的关注有序集合中添加元素

zadd my_id."follow" time() follow_id //my_id为关注者id 、time() 为当前关注的时间戳、 follow_id为被关注者id

2、将my_id加入到follow_id的粉丝列表中

zadd follow_id."fans" time() my_id 
取消关注

1、将该id从我的关注列表中移除

zrem my_id."follow" follow_id

2、将my_id从follow的粉丝列表中移除

zrem follow_id."fans" my_id
获取我的关注列表
zrange my_id."follow" 0 -1
获取我的粉丝列表
zrange my_id."fans" 0 -1

下面为具体代码的实现,这里我使用了redis和mysql来进行实现,使用的还是CI框架,里面使用了事务操作来实现数据的一致性,这里主要是数据库数据的一致性,我新建了一个follow表,为关注表,又在users表中增加了follow和fans字段,一个为关注人数,一个为粉丝数,这里的关注操作需要操作多个表,所以需要保证数据的一致性。redis我在关注、取消关注、获取关注、粉丝列表,都有对redis和数据数据库数据做统一操作

控制器代码
/*
* 关注/取消关注
*/
public function follow()
{
    $rules = [
        [
            'field' => 'user_id',
            'label' => '关注者id',
            'rules' => 'required|numeric',
            'errors' => [
                'required' => '关注者id不能为空.',
                'numeric' => '关注者id必须为数字.'
            ]
        ],
        [
            'field' => 'follow_id',
            'label' => '被关注者id',
            'rules' => 'required|numeric',
            'errors' => [
                'required' => '关注者id不能为空.',
                'numeric' => '关注者id必须为数字.'
            ]
        ],
        [
            'field' => 'type',
            'label' => '类型',
            'rules' => 'required|in_list[1,2]',
            'errors' => [
                'required' => '类型不能为空.',
                'in_list' => 'type只能为1,2'
            ]
        ]
    ];
    $data = $this->input->post();
    $this->form_validation->set_data($data);
    $this->form_validation->set_rules($rules);
    if ($this->form_validation->run() == FALSE) {
        $data = $this->form_validation->error_array();
        $data = current($data);
        fail('400', $data);
    }
    $sta1 = $this->users_model->checkUser($data['user_id']);
    $sta2 = $this->users_model->checkUser($data['follow_id']);
    $res = $this->users_model->is_follow($data);
    //连接redis
    $conn = getRedis();
    $conn->selectDb(0);
    //我的关注集合key
    $key = $data['user_id'] . '_follow';
    $key2 = $data['follow_id'] . '_fans';
    //从缓存中读取我的全部关注列表
    $follows = $conn->zRange($key2, 0, -1);

    if (!$sta1 || !$sta2) {
        fail(400, '该用户不存在!');
    }

    //关注
    if ($data['type'] == 1) {
        if ($res) {
            fail(400, '该用户您已经关注!');
        }
        //关注数据库操作
        unset($data['type']);
        $res2 = $this->users_model->follow($data);
        if (!$res2) {
            fail(400, '操作出错!');
        }
        //关注的redis操作
        if (!empty($follows)) {
            if (in_array($data['user_id'], $follows)) {
                fail(400, '该用户已经被关注!');
            }
        }
        //添加到我的关注集合
        $res1 = $conn->zAdd($key, [time() => $data['follow_id']]);
        if (!$res1) {
            fail(400, '关注失败!');
        }
        //添加到他的粉丝集合
        $res2 = $conn->zAdd($key2, [time() => $data['user_id']]);
        if (!$res2) {
            fail(400, '关注失败!');
        }
        success($res2, '关注成功!');
    } else {
        //取消关注操作
        unset($data['type']);
        if (!$res) {
            fail(400, '该用户您未关注!');
        }
        //数据库操作
        $res2 = $this->users_model->unFollow($data);
        if (!$res2) {
            fail(400, '操作出错!');
        }
        //取消关注的redis操作
        if (!empty($follows)) {
            if (!in_array($data['user_id'], $follows)) {
                fail(400, '该用户您未关注!');
            }
        }
        //从自己的关注列表移除
        $res1 = $conn->zRem($key, [$data['follow_id']]);
        if (!$res1) {
            fail(400, '取消关注失败!');
        }
        //从他的粉丝集合移除
        $res2 = $conn->zRem($key2, [$data['user_id']]);
        if (!$res2) {
            fail(400, '取消关注失败!');
        }
        success($res2, '取消关注成功!');
    }
}

/*
* 获取关注列表
*/
public function followList()
{
    $data = $this->input->post();
    if (empty($data['id'])) {
        fail(400, '获取失败!');
    }
    //先从redis中获取关注列表
    $conn = getRedis();
    $conn->selectDb(0);
    $key = $data['id'] . '_follow';
    $key2 = $data['id'] . '_fans';
    $id_array = $conn->zRange($key, 0, -1);
    $fans_array = $conn->zRange($key2, 0, -1);
    //redis中未获取到,在数据库中获取
    if (empty($id_array)) {
        $res1 = $this->users_model->followList($data['id']);
        $id_array = $res1 ? array_column($res1, 'follow_id') : null;
    }
    //没有关注的人
    if ($id_array == null) {
        success(null);
    }
    //根据id查询用户基本信息
    $res = $this->users_model->getUserInfoByIds($id_array);
    //获取该用户是否已经关注了你
    foreach ($res as $k => &$v) {
        if (empty($fans_array)) {
            $res[$k]['status'] = 0;
        } else {
            if (in_array($v['id'], $fans_array)) {
                //互相关注
                $res[$k]['status'] = 1;
            } else {
                //未互相关注
                $res[$k]['status'] = 0;
            }
        }
    }
    success($res, '获取成功!');
}

/*
* 获取粉丝列表
*/
public function fansList()
{
    $data = $this->input->post();
    if (empty($data['id'])) {
        fail(400, '参数错误!');
    }
    $sta = $this->users_model->checkUser($data['id']);
    if (!$sta) {
        fail(400, '该用户不存在!');
    }
    $conn = getRedis();
    $conn->selectDb(0);
    //缓存中获取粉丝列表
    $key = $data['id'] . "_fans";
    $fans_list = $conn->zRange($key, 0, -1);
    //缓存中未获取到
    if (empty($fans_list)) {
        $res = $this->users_model->fansList($data['id']);
        if ($res == null) {
            //没有粉丝
            success(null);
        }
        $fans_list = array_column($res, 'user_id');
        //将该数据写入缓存中
        $res1 = $conn->zAdd($key, $fans_list);
        if (!$res1) {
            fail(400, '操作失败!');
        }
    }
    //通过获取到的粉丝列表id,查询用户的基本信息
    $result = $this->users_model->getUserInfoByIds($fans_list);
    //查看我的粉丝是否关注了我
    $key2 = $data['id'] . '_follow';
    $follow_list = $conn->zRange($key2, 0, -1);
    //缓存中未获取到
    if (empty($follow_list)) {
        $res3 = $this->users_model->followList($data['id']);
        if (empty($res3)) {
            $follow_list = null;
        } else {
            //若数据库中查到
            $follow_list = array_column($res3, 'follow_id');
            if (!empty($follow_list)) {
                $status = $conn->zAdd($key2, $follow_list);
                if (!$status) {
                    fail('400', '操作失败!');
                }
            }
        }
    }
    foreach ($result as $k => &$v) {
        if (empty($follow_list)) {
            $result[$k]['status'] = 0;
        } else {
            in_array($v['id'], $follow_list) ? $result[$k]['status'] = 1 : $result[$k]['status'] = 0;
        }
    }
    $result ? success($result, '获取粉丝列表成功!') : fail(400, '获取粉丝列表失败!');
}

模型代码
   public function is_follow($data)
    {
        //判断该用户是否已经关注该主播
        $query = $this->db->select('user_id')
            ->where('user_id', $data['user_id'])
            ->where('follow_id',$data['follow_id'])
            ->get('follow');
        //判断该用户
        return $query->num_rows() ? true : false;
    }

    public function follow($data)
    {
        //这里需要开启事务操作,首先将数据插入follow表中,然后更新用户的粉丝数量有一步出错就回滚事务
        //开启事务
        $this->db->trans_begin();
        //更新用户表中的用户粉丝数
        $sql1 = "update users set fans = fans+1 where id = " . $data['follow_id'];
        $this->db->query($sql1);
        //跟新用户表中的用户关注数
        $sql2 = "update users set follow = follow+1 where id = " . $data['user_id'];
        $this->db->query($sql2);
        //数据插入follow表中
        $data['create_time'] = time();
        $this->db->insert('follow', $data);
		//所有的sql执行出现错误
        if ($this->db->trans_status() === false) {
            //数据回滚
            $this->db->trans_rollback();
        } else {
            //为出错则提交修改
            $this->db->trans_commit();
        }
        return $this->db->trans_status() ? true : false;
    }

    public function unFollow($data)
    {
        //这里需要开启事务操作,首先将数据插入follow表中,然后更新用户的粉丝数量有一步出错就回滚事务
        //开启事务
        $this->db->trans_begin();
        //更新用户表中的用户粉丝数
        $sql1 = "update users set fans = fans-1 where id = " . $data['follow_id'];
        $this->db->query($sql1);
        //跟新用户表中的用户关注数
        $sql2 = "update users set follow = follow-1 where id = " . $data['user_id'];
        $this->db->query($sql2);
        //数据插入follow表中
        $this->db->delete('follow', ['user_id' => $data['user_id'], 'follow_id' => $data['follow_id']]);

        if ($this->db->trans_status() === false) {
            $this->db->trans_rollback();
        } else {
            $this->db->trans_commit();
        }
        return $this->db->trans_status() ? true : false;
    }

    public function followList($id)
    {
        $query = $this->db->select('follow_id')
            ->where('user_id',$id)
            ->get('follow');
        return $query->num_rows() ? $query->result_array() : false;
    }

    public function getUserInfoByIds($ids)
    {
        $query = $this->db->select('id,nickname,image,sign')
            ->where_in('id', $ids)
            ->get('users');
        return $query->num_rows() ? $query->result_array() : false;
    }

    public function fansList($id){
        $query = $this->db->select('user_id')
            ->where('follow_id',$id)
            ->get('follow');
        return $query->num_rows() ? $query->result_array()  : false;
    }

实现效果,这里我只完成了接口的编程,vue的页面还未编写,所以在postman请求接口查看操作,这里的参数为当前用户id,关注者id,以及type来判断是关注操作,还是取消关注操作。

关注:

在这里插入图片描述

取消关注:

在这里插入图片描述

查看粉丝列表

这里status为该用户是否关注了我,关注了为1,未关注为0

在这里插入图片描述

这样就实现了关注与取消关注操作,这个功能让我对于细节的把控更加深入,对于任何一种条件该进行操作,以及该怎么返回数据有了很深入的了解。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值