点赞功能:从数据库设计到Web端实现分析

点赞功能需求:用户能点赞,能取消赞,同时能查看赞了该条状态的所有人,可能还需要提醒发该条状态的人谁谁谁赞了你。
web端实现:显示点赞数,当有用户赞了该状态,则点赞数+1等。
本文从点赞功能的数据库设计说起,一步步到各个功能的基本实现方法。

数据库设计

首先是2张表,t_user表与t_tatus表,分别表示用户表与状态表。Ps:这个点赞功能是需要登录的。(如果是不需要登录就能点赞,最好还需要多个字段或新表来记录用户IP,防止重复点赞)
那么关键是点赞功能怎么在数据库中表现出来。

刚开始我觉得直接在t_tatus表中加一个like字段,当有用户点了赞,直接拼个user_id组成的字符串,用逗号隔开, 形如1,2,3,4写入即可。麻烦的是每次写入新的id都要重新拼一次字符串,取消赞也要操作一次字符串,每次取得赞的所有人也要处理字符串,每次计算赞的人数也要拆一次字符串。
当是这种写法也不是没好处,节省空间,不用新表,数据库开销小。无非计算字符串来来回回比较浪费时间。
为了以后查询好处理一点,我的实现还是新建了一张t_like表(有新方案的小伙伴可以评论留言讨论),结构如下。

表t_user结构:

1
2
3
4
5
6
7
8
CREATE TABLE `t_user` (
`userID` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL UNIQUE,
`nickname` varchar(255) DEFAULT NULL ,
`pwd` varchar(255) NOT NULL ,
`phoneno` varchar(64) DEFAULT NULL ,
PRIMARY KEY (`userID`)
)

表t_tatus结构:

1
2
3
4
5
6
CREATE TABLE `t_tatus` (
`statusID` int(11) NOT NULL AUTO_INCREMENT,
`userID` int(11) NOT NULL ,
`statusContent` varchar(255) NULL DEFAULT NULL ,
PRIMARY KEY (`statusID`)
)

表t_like结构:(双主键)

1
2
3
4
5
6
CREATE TABLE `t_like` (
`statusID` int(11) NOT NULL ,
`userID` int(11) NOT NULL ,
`createTime` varchar(45) NULL DEFAULT NULL ,
PRIMARY KEY (`statusID`,`userID`)
)

服务器端

服务器端主要做的就是点赞时在t_like表中插入一条数据,取消赞时找到t_like表中的对应数据删除,很easy。PS:可能还需要统计赞的个数并返回,sql语句count()一下。
文件名like.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
require_once('common.php');
//http:localhost/like.php?userID=1&statusID=1&getMethod=web&do=auto
$userID = $_GET['userID'];
$statusID = $_GET['statusID'];
$getMethod = $_GET['getMethod']; //请求方式, 如果是web, 则返回地址
$do = $_GET['do']; //like 或者 unlike 或者 auto(自动判断)
if (!isset($userID) || !isset($statusID)) {
return Response::show(401, '参数不合法');
eixt();
}
//登录检测
//xxxx
try {
$connect = Db::getInstance()->connect();
} catch (Exception $e) {
return Response::show(403, '数据库连接失败');
}
function do_like($connect,$getMethod,$statusID,$userID){
$nowTime = date('Y-m-d H:i:s', time());
$sql = "INSERT INTO t_like(statusID,userID,createTime) VALUES ($statusID,$userID,'$nowTime')";
$result = mysql_query($sql, $connect);
if ($result) {
if ($getMethod == "web") {
echo "Y";
}
} else {
return Response::show(402, '点赞失败');
}
}
function do_unlike($connect,$getMethod,$statusID,$userID){
$sql = "delete from t_like where statusID=$statusID and userID=$userID";
$result = mysql_query($sql, $connect);
if ($result) {
if ($getMethod == "web") {
echo "N";
}
} else {
return Response::show(403, '取消赞失败');
}
}
if($do == "auto"){
//1.判断是否赞过.赞过->取消赞; 未赞过, 点赞.
$sql = "SELECT createTime FROM t_like WHERE statusID=$statusID and userID=$userID";
$query = mysql_query($sql,$connect);
if ($query) {
if ($rs = mysql_fetch_array($query)) {
//有值, 表示已经赞
do_unlike($connect,$getMethod,$statusID,$userID);
}else {
//未赞
do_like($connect,$getMethod,$statusID,$userID);
}
} else {
return Response::show(401, '查询失败');
}
}else
if ($do == "like") {
do_like($connect,$getMethod);
} else if ($do == "unlike") {
do_unlike($connect,$getMethod,$statusID,$userID);
} else {
return Response::show(401, '参数不合法');
}

common.php文件中包含了一些封装的返回信息,数据库连接封装。

web端

Ajax实现web端点赞

1
<button id = "zanName" onclick="demo()"></button>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<script>
ajax点击更新赞的数目
function demo() {
//1.创建XMLHttpRequest 对象
var xmlhttp;
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
}
else {// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
//2.发送get请求
xmlhttp.open("GET", "like.php?userID=1&statusID=1&getMethod=web&do=auto", true);
xmlhttp.send();
//3.获取响应并显示
//如果来自服务器的响应并非 XML,请使用 responseText 属性。
//如果来自服务器的响应是 XML,而且需要作为 XML 对象进行解析,请使用 responseXML 属性.
//document.getElementById("myDiv").innerHTML = xmlhttp.responseText;
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var isLike = xmlhttp.responseText;
if(isLike == 'Y'){
document.getElementById("zanName").innerHTML = "已赞";
}else if(isLike == 'N'){
document.getElementById("zanName").innerHTML = "赞";
}
}
}
}
</script>

通过获取服务器返回的Y,或者N来自动判断是否点过赞。点过赞则显示已赞,再次点击则取消赞。

扩展

可以用客户端Cookie记录用户是否点赞,也可以用Session判断用户是否登录,并记录用户是否点赞。然后再对数据库进行操作。

结语

潜在问题

因为实际需求中点赞数量可能很庞大,多用户+多status时更是惊人。使得这张t_like表可能变得巨大,且没必要,那么如何解决?

我的优化思路

定期清理t_like表中的数据,如用户删除了status的;时间过去久远的status可以只记录点赞的总条数,把对应的t_like中数据删除。

功能不尽完善,实际需求时很多细节功能要复杂很多,本文仅提供一些思路,不贴完整代码。

转载请注明出处,有疑问欢迎留言!