我正在为类似博客的网站上的帖子创建投票系统。
每个帖子都会有一个评分,存储在数据库中。用户可以单击以投票或降票,数据库中的数字将增加或减少。简单的东西。
但是,如何检查当前用户是否已经投票?
我最初的想法是在数据库中为每个帖子创建两个额外的列“ UsersUp”和“ UsersDown”,以存储对每个帖子投票赞成和反对的用户名。我会检查用户名是否存在,如果存在,将删除投票,而不是添加另一个投票。我什至可以完全删除“ rating”列,并通过只计算UsersUp中用户名的数量并减去UsersDown中用户名的数量来实现相同的目的。
我是否以错误的方式处理此问题?
我没有要求任何代码,只是要求实现该目标的理论。
我需要用户不能上下投票两次,并且他们需要能够通过再次单击来撤回投票。
您应该使用规范化的数据库设计。
您可能有一张User
桌子,根据这个问题,您有一张Post
桌子。
您可以使用第三个UserVote
表格来表示用户,帖子及其投票之间的关系。这允许对投票者,投票时间和投票方式进行细化跟踪(VoteTypeId可以包含赞成或反对投票的ID)。
+--------+--------+------------+----------+
| UserId | PostId | VoteTypeId | VoteDate |
+--------+--------+------------+----------+
| 1 | 1 | 1 | 1/1/2017 |
+--------+--------+------------+----------+
| 2 | 1 | 1 | 2/1/2017 |
+--------+--------+------------+----------+
| 3 | 1 | 2 | 2/2/2017 |
+--------+--------+------------+----------+
这将对数据建模。您应该如何从c#调用它?
if( !HasVoted( userId, postId ) ){
SaveVote( userId, postId, voteTypeId );
UpdateVoteCount( postId, voteTypeId );
}
但是,这很容易出错。如果UpdateVoteCount()
失败怎么办?
有多种方法可以解决此问题,其中包括:
using( var scope = new TransactionScope() ){
if( !HasVoted( userId, postId ) ){
SaveVote( userId, postId, voteTypeId );
UpdateVoteCount( postId, voteTypeId );
}
scope.Complete();
}
阅读更多:TransactionScope
这有助于提高数据完整性,但是代码仍然具有争用条件,使系统容易被滥用。
我们需要锁定整个操作。一种实现此目的的方法是使用存储过程sp_getapplock
,该存储过程使您可以阻止命名的资源,直到锁的持有者释放它为止。
您可以使用一个命名的锁,也可以对每个项目进行锁定(如果对一个项目进行投票,可能会产生更广泛的后果,例如声誉计算,这很麻烦)。
阅读更多:sp_getapplock
我们的顺序变为:
虽然这听起来很复杂,并且锁定听起来像是一个瓶颈,但实际上却表现不错。几年前,我对该设计进行了压力测试,轻松实现了每秒2500次以上的投票操作吞吐量。
调用代码应确保:
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句