投票代码PHP实例
增加投票事务控制
思路讲解:
* 投票有效期为 86400*7
* 一个赞的分值为 86400 / 200 = 432
*
* hash 存储文章的内容, key为文章的id
* zset key为文章id,score为文章发布时间,存时间戳
* zset key为文章id,score为文章的分值
* set 记录投票用户与对应文章
完整代码:
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2021/9/8
* Time: 10:01
*/
class Vote
{
private $redis;
const SCORE = 432; // 此方式可以在输出文章详情的给出,这里没有计算
const VOTE_EXPIRE_TIME = 86400 * 7;
const PARAM_ERROR = '参数错误';
public function __construct()
{
$this->redis = new Redis();
$this->redis->connect('172.17.0.3','6379','5');
//$this->redis->connect('127.0.0.1','6379','5');
$this->redis->select(7);
}
// 发布文章
public function postArticle($content) {
$author_id = $content['poster']; // 作者id
// 这里使用了incr自增的操作
$article_id = $this->redis->incr('article:'); // 文章id
// 添加文章
$article_key = 'article:'.$article_id;
// 文章发布开启一个事务
$this->redis->hMSet($article_key, $content);
// 将文章添加到发布时间有序集合中
$this->redis->zAdd("time:",time(),$article_key);
// 将文章添加到分数有序集合中
$this->redis->zAdd("score:",1, $article_key);
// 创建投票集合,并将作者添加进去
$this->redis->sAdd("vote:".$article_id, $author_id);
// 设置投票集合的有效期
$this->redis->expire("vote:".$article_id, self::VOTE_EXPIRE_TIME);
return $article_id;
}
// 给文章投票
// $vote_id 投票用户id
// $article_id 文章id
public function voteArticle($vote_id, $article_id) {
$article_key = 'article:'.$article_id;
$vote_key = 'vote:'.$article_id;
// 判断文章是否存在
if (!$this->redis->exists($article_key)) {
echo '未找到文章信息!';
exit();
}
// 判断是否过投票期
$cutOff = time() - self::VOTE_EXPIRE_TIME;
$post_time = $this->redis->zScore("time:",$article_key);
if ($post_time < $cutOff) {
echo '投票时间已过!';
exit();
}
try {
$this->redis->watch($article_key); // 监视文章的key,一旦发生改变就跳出
if ($this->redis->sIsMember($vote_key, $vote_id)) {
$this->redis->unwatch($vote_key);
echo '已投票!不能重复投票';
exit();
}
$this->redis->multi();
$this->redis->sAdd($vote_key,$vote_id);
$this->redis->zIncrBy("score:",1, $article_key);
$this->redis->hIncrBy($article_key,'votes',1);
$this->redis->exec();
echo "投票成功";
exit();
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
}
// 获取文章列表
public function getArticle($page = 1, $size = 10, $order='score:') {
$start = ($page - 1) * $size;
$end = $start + $size - 1;
$ids = $this->redis->zRevRange($order, $start, $end);
foreach ($ids as $id) {
$data = $this->redis->hGetAll($id);
$data['article_id'] = $id;
$articles[] = $data;
}
return $articles;
}
// 将文章加入到不同的分组中,或者从分组中移除
public function addOrRemoveGroup($article_id, $group_id=[], $type = 'add') {
$article_key = "article:".$article_id;
$op = $type=='add' ? 'sAdd' : 'sRem';
foreach ($group_id as $item) {
$this->redis->$op("group:".$item, $article_key);
}
echo $op . '成功';
}
// 获取不同分组的文章
public function getGroupArticle($orders="score:", $group_id) {
$save_key = "new_group:".$orders . $group_id.":".session_id();
if (!$this->redis->exists($save_key)) {
$this->redis->zinterstore($save_key, ["group:".$group_id, $orders]);
}
$list = $this->getArticle(1,3, $save_key);
$this->redis->del($save_key);
return $list;
}
}
// 测试部分
// 分组 1-redis 2-php 3-mysql
$vote = new Vote();
// 这里数据可以重复构造
/*$article_content = [
'title' => 'mysql基础_2',
'link' => 'http://www.baidu.com',
'poster' => 'user:2',
'time' => time(),
'votes' => 1
];
print_r($vote->postArticle($article_content));*/
// 投票
//echo $vote->voteArticle("user:1",1);
// 获取文章列表
/*$list = $vote->getArticle(1,3,"time:");
echo "<pre>";
print_r($list);
echo "<pre>";*/
// 文章分组
//$vote->addOrRemoveGroup(1,[1],'add');
//$vote->addOrRemoveGroup(3,[1],'add');
// 输出分组文章
/*$list = $vote->getGroupArticle("score:",1);
echo "<pre>";
print_r($list);
echo "<pre>";*/