PHP 遇到了一个匪夷所思的问题

2017-11-01 15:56:01 +08:00
 frozenway
写一个用于统计网站访问信息的功能时,遇到了个问题:
-->我的思路是这样的:当网站有人访问时,判断数据表里是否有记录今天访问的信息,如果没有着新建一条记录,然后就在访问量上+1 ;如果已经有记录了,着直接在访问量上+1 ;代码如下:

//统计访问次数
protected function ttVisit($aid){
if(is_numeric($aid)){
$model = M('monitor');
$row = $model->where(['aid'=>$aid, 'xdate'=>date('Y-m-d')])->field('moid')->find();
if(!$row){
$row['moid'] = $model->data(['xdate'=>date('Y-m-d'), 'aid'=>$aid])->add();
if(!$row['moid']){
return false;
}
}
$model->where(['moid'=>$row['moid']])->setInc('top');
return $row['moid'];
}
return false;
}

其中$aid 是对应某个网站的 ID,top 是数据库字段,表示访问量。xdate 是要统计访问量的日期。
好了,这样的逻辑一点问题都没有,但是真正运行起来,理想状态数据表应该是这样的:

id aid xdate top
1 1 2017-11-01 20
2 2 2017-11-01 100
3 5 2017-11-01 96

然而现实运行起来是这样的

id aid xdate top
1 1 2017-11-01 1
2 1 2017-11-01 19
3 2 2017-11-01 100
4 5 2017-11-01 94
5 5 2017-11-01 1
6 5 2017-11-01 1

为什么理想和现实差距这么大?
是我的逻辑有问题了吗?
3162 次点击
所在节点    PHP
13 条回复
b821025551b
2017-11-01 16:02:19 +08:00
并发问题,要加锁。
zjsxwc
2017-11-01 16:08:56 +08:00
用队列处理更方便
frozenway
2017-11-01 16:11:01 +08:00
@b821025551b 数据库是 MyISAM,加不了锁
frozenway
2017-11-01 16:12:38 +08:00
@zjsxwc 没接触过队列,能说清楚点吗?
b821025551b
2017-11-01 16:14:15 +08:00
两个解决方案:
1:上队列;
2:做个定时任务,比如今天凌晨 3 点把明天的数据顺序的 add 一遍,保证明天的数据在明天只有 update 操作。
sagaxu
2017-11-01 16:24:28 +08:00
加唯一索引(aid, xdate),然后用 upsert(insert-on-duplicate)

顺便问一句,楼主你是来黑 PHP 的吗?
vescape920
2017-11-01 16:24:33 +08:00
不知道我理解的对不对 就是每个用户每天第一次访问时 insert 记录 之后是 update 该条记录
你可以把 user_id 和 date 建一个 unique 索引 在写 sql 的时候使用 ON DUPLICATE KEY UPDATE
akira
2017-11-01 16:28:35 +08:00
aid 和 xdate 做个复合主键 ,代码什么的完全不用动了。
缺点是会丢部分数据
frozenway
2017-11-01 16:34:46 +08:00
@akira
@vescape920
@sagaxu @b821025551b
多谢大神指点
fcten
2017-11-01 17:01:28 +08:00
mysql 是 php 不可分割的一部分!(滑稽.jpg
fcten
2017-11-01 17:04:23 +08:00
顺便,这样统计访问量性能非常差,建议做合理缓存
yxn1910
2017-11-01 17:16:10 +08:00
访问次数这样的非敏感数据建议先缓存,定时入库,在这里使用事务性价比太低。
linpf
2017-11-01 17:29:26 +08:00
并发量太大,在第一次请求时,数据库判断没有记录,然后再插入新纪录的时候,第二次请求也通过了有无记录的判断,导致重复插入。

最好的办法是加锁。但是加锁也不必依赖数据库。使用 TP 框架的缓存做一个简单的锁也可以。不妨试一下。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/402652

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX