概述php文件锁产生的问题和解决方案(一个真实案例) 一个真实案例
想起自己之前犯过一个相关的错误。当时场景是这样的:有一个微信公众号项目,调用微信公众号的接口都需要access_token
,它的有效期是2小时。当时我的做法是把它存放在文件中,格式使用的是Json
。{"access_token":"easWasDW32323", "expire":1588219064}
。伪代码如下:
function getToken ($tokenfile){ $tokenjson = file_get_contents($tokenfile); if (!$tokenjson) { $token = loadToken($tokenfile); } else if (Json_decode($tokenjson, true)['expire'] <= time()){ $token = loadToken($tokenfile); } else { $token = Json_decode($tokenjson, true)['access_token']; } return $token;}function loadToken ($tokenfile) { $fp = fopen($tokenfile, 'r+'); $tokenjson = ...; // 调用微信接口获取到token fwrite($fp, Json_encode($tokenjson)); return $tokenjson['access_token'];}
出现的问题:
项目运行一段时间后就会出问题,但过一两秒后再刷新就正常了。
问题原因分析:
假设token已经过期了,这时候有2个请求来了,分别命名为A、B。A来了,发现token到期后,去调用微信接口获取新的token,获取后,更新到存放token的文件中。
但是,文件没有完全更新完毕的时候,B来了,读入存放token的文件。因为token文件中数据没有更新完整,B读到的数据就会产生错误。
另外还有可能是A和B同时在更新文件内容,这样就会产生数据混乱,也会导致错误发生。
如何规避这个错误呢?
文件锁机制可以完成。
在PHP中提供了 flock()函数,可以对文件使用锁定机制(锁定或释放文件)。当一个进程在访问文件时加上锁,其他进程要想对该文件进行访问,则必须等到锁定被释放以后。这样就可以避免在并发访问同一个文件时破坏数据。
函数原型如下:
flock ( resource $handle , int $operation [, int &$wouldblock ] ) : bool
handle
:
文件系统指针,是典型地由 fopen() 创建的 resource(资源)。
operation
operation 可以是以下值之一:
LOCK_SH取得共享锁定(读取的程序)。
LOCK_EX 取得独占锁定(写入的程序)。
LOCK_UN 释放锁定(无论共享或独占)。
LOCK_NB附加锁定(windows 上还不支持)。
wouldblock
如果锁定会堵塞的话(EWOulDBLOCK 错误码情况下),可选的第三个参数会被设置为 TRUE。(windows 上不支持)
demo
demo1.PHP
<?PHP $file = 'data.txt';$handler = fopen($file, 'a+') or dIE('文件资源打开失败');// 取得独占锁if (flock($handler, LOCK_EX)) { sleep(5); flock($handler, LOCK_UN);} else { echo '锁定失败';} fclose($handler);
demo2.PHP
<?PHP$file = 'data.txt';$handler = fopen($file, 'a+') or dIE('文件资源打开失败'); // 取得独占锁if (flock($handler, LOCK_EX)) { fwrite($handler, 'sometest string'); flock($handler, LOCK_UN);} else { echo '锁定失败';} fclose($handler);
先运行demo1.PHP然后立即运行demo2.PHP,会发现,因为被demo1.PHP锁定了文件,demo2.PHP写入不了新内容,只有等demo1.PHP释放了锁定,demo2.PHP才能拿到独占锁,然后才能写入文件。
解决问题
学完这些知识后,就能解决我之前的问题了。改进的代码如下:
<?PHPfunction getToken ($tokenfile){ $tokenjson = file_get_contents($tokenfile); if (!$tokenjson) { $token = loadToken($tokenfile); } else if (Json_decode($tokenjson, true)['expire'] <= time()){ $token = loadToken($tokenfile); } else { $token = Json_decode($tokenjson, true)['access_token']; } return $token;}function loadToken ($tokenfile) { $fp = fopen($tokenfile, 'w'); // 取得独占锁 if (flock($fp, LOCK_EX)) { $tokenjson = ...; // 调用微信接口获取到token fwrite($fp, Json_encode($tokenjson)); flock($fp, LOCK_UN); } else { return false; } return $tokenjson['access_token'];}
总结
以上是内存溢出为你收集整理的php文件锁产生的问题和解决方案(一个真实案例)全部内容,希望文章能够帮你解决php文件锁产生的问题和解决方案(一个真实案例)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
请登录后查看评论内容