PHP高并发下防重复执行有五种方法:一、文件锁flock();二、Redis分布式锁;三、MySQL行级锁;四、信号量文件+时间戳校验;五、Nginx限流。

如果PHP脚本在高并发场景下被重复触发,可能导致数据库写入冲突、资源争用或业务逻辑异常。以下是限制PHP脚本并发执行的多种方法:
一、使用文件锁机制
通过flock()函数对指定文件加独占锁,确保同一时刻仅有一个进程能进入临界区执行脚本主体逻辑。
1、创建一个专用锁文件路径,例如/tmp/script.lock。
2、在脚本开头使用$fp = fopen('/tmp/script.lock', 'c');打开文件。
3、调用flock($fp, LOCK_EX | LOCK_NB)尝试获取非阻塞排他锁。
4、若返回false,说明锁已被占用,立即退出并输出并发请求已被拒绝。
5、执行完核心逻辑后,调用flock($fp, LOCK_UN)释放锁,并关闭文件句柄。
二、基于Redis的分布式锁
利用Redis的SET命令配合NX和EX选项实现原子性加锁,适用于多服务器部署环境。
1、生成唯一锁键名,例如lock:process_order。
2、执行SET lock:process_order "1" NX EX 30,设置30秒过期时间。
3、若返回OK,表示加锁成功,继续执行脚本;若返回nil,说明锁已存在,直接终止。
4、脚本结束前调用DEL lock:process_order释放锁。
5、为防止锁持有者异常退出,所有操作必须严格遵循加锁-执行-解锁流程,并确保锁的过期时间大于脚本最大预期执行时间。
三、数据库行级锁控制
借助MySQL的SELECT ... FOR UPDATE语句,在事务中锁定特定记录,阻止其他并发事务修改同一行。
1、在数据库中创建一张专用控制表,如concurrent_lock,含字段task_name(主键)和locked_at。
2、开启事务后执行SELECT locked_at FROM concurrent_lock WHERE task_name = 'my_script' FOR UPDATE。
3、若查询结果为空,需先INSERT该记录再继续;若查询到记录且locked_at距今未超时,则退出并提示任务正在运行中,请稍候重试。
4、若可执行,则更新locked_at为当前时间戳,并提交事务。
5、脚本完成时再次更新该记录,清空或标记为已完成状态。
四、信号量文件+时间戳校验
结合文件存在性与内容中的时间戳判断是否允许执行,避免因进程崩溃导致锁长期残留。
1、定义锁文件路径/tmp/script.sem。
2、检查文件是否存在,若不存在则创建并写入当前时间戳后继续。
3、若文件存在,读取内容解析为UNIX时间戳,计算与当前时间差。
4、若差值小于设定阈值(如60秒),则拒绝执行并返回上一次执行尚未完成。
5、若差值超过阈值,视为过期锁,覆盖写入新时间戳后继续执行。
五、Web服务器层限流(Nginx)
在反向代理层拦截高频请求,从入口处减少PHP脚本被并发调用的可能性。
1、在Nginx配置中定义limit_req_zone,例如limit_req_zone $binary_remote_addr zone=php_limit:10m rate=1r/s。
2、在location块中添加limit_req zone=php_limit burst=3 nodelay。
3、设置返回状态码为503,并自定义错误页面提示用户请求过于频繁,请降低调用频率。
4、确保PHP脚本URL路径匹配该location规则,使限流策略生效。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











