PHP 遇到了一个匪夷所思的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
frozenway
V2EX    PHP

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

  •  
  •   frozenway 2017-11-01 15:56:01 +08:00 3677 次点击
    这是一个创建于 2959 天前的主题,其中的信息可能已经有所发展或是发生改变。
    写一个用于统计网站访问信息的功能时,遇到了个问题:
    -->我的思路是这样的:当网站有人访问时,判断数据表里是否有记录今天访问的信息,如果没有着新建一条记录,然后就在访问量上+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

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

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

    最好的办法是加锁。但是加锁也不必依赖数据库。使用 TP 框架的缓存做一个简单的锁也可以。不妨试一下。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5433 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 40ms UTC 06:06 PVG 14:06 LAX 22:06 JFK 01:06
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86