下单,充值问题
3个用户几乎同一时候下的订单,下单成功。发现下单时间分别是10:00:01,10:00:02,10:00:03,每个相隔1秒。但不知道什么原因了,在选取支付码的时候。3个同时发现17.59是空闲状态。
$mQP = M('Qp');
$where['is_use'] = 1
$rQP = $mQP->where($where)->find();//3个php-fpm进程同时运行到此处,发现is_use=0,于是内存里的$rQR值就是17.59这条。
if(!empty($rQP )){ //3个php-fpm进程同时发现$rQ非空,也同时进入了if里
$transfer_id = $rQP ['id'];
$data = [];
$data['id'] = $transfer_id;
$data['is_use'] = 1;
$data['user_id'] = $user_id;
$data['order_id'] = $order_id;
$data['status'] = 1;//待支付
$mQP->save($data); //3个进程依次运行到此处,创建了3个订单,成功的把1个支付码资源,同时分配给了3个用户。这就是问题所在。
}
在订单和支付过程中,经常出现同时处理同一条记录问题,所以一般就要给我条记录加锁,已经被人使用了,则立马锁上,不能让其它进程再随意的读取,更新状态了。
比如下单成功后,用户支付后,有个服务器通知和回调。由于有时通知没有通知到,回调也没成功。则需要自己去支付平台提供的接口上去轮询。但此时,若轮询和回调同时运行了,同时发现订单是未支付,然后给同时给他设为已支付,并充值开通会员。这样就很容易的就开通2次了。
一般用乐观锁好可解决,thinkphp框架本身也提供这个功能,只要继承下AdvModel即可。
还有个要留意的就是,mysql默认时间一般用current_timestamp或用php的time(),在查找日志时有时发现同一秒有多个请求,可以用php的microtime来获取微秒数,然后再入库。
/* * *返回当前 Unix 时间戳和微秒数(用秒的小数表示)浮点数表示,常用来计算代码段执行时间 */ function microtime_float() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); }