关于 PHP 插入数据库如果该接口访问多次可能会插入多次的思考
前言
今晚在搞一个用户注册的接口,突然发现如果该注册接口在一定的时间内访问多次,有可能注册多次,由此来水一篇文章
因为这是为了和同学联合做个(我负责网页端、服务端,他负责 Android 端),不能搞得太复杂比如搞个验证码、Session 验证之类的,不然一个 App 注册页面得做好久,循序渐进,先做好基础功能再做这些高级点的
主机配置
- Arm64 开发板(也就是我家云啦,2020年1月初,70+元在咸鱼捡的矿渣),1GB 内存,配置很垃圾,搭建一些小网站、测试代码还是勉勉强强的
在宝塔面板装了两次不同版本的,总共花费2个多小时,都失败了,太难受了。
但最后得用的 Docker,网上搜了下相关镜像,有人做了 Arm64 版本的MySQL 5.7
的镜像,拉取镜像、配置、运行,一气呵成。
Docker 部署确实太方便了。
可惜自己花费大量时间去编译装 MySQL,结果以失败告终…
相关注册逻辑
//1. 判断用户名和密码是否合规
//2. 判断该用户名是否被注册
//3. 插入数据库
//4. 判断是否注册(插入数据库)成功
这样看上去似乎没什么问题,但是当我测试的时候,一不小心多按了几次刷新,结果数据表里出现了几个一摸一样的用户名。
然后想了想这可能是因为自己主机太垃圾了,插入数据库都要执行那么久…
当然遇到这个问题,肯定是要解决的了,首先想到了用 Redis 弄一个锁,再怎么的也比主机硬盘速度快吧,然后注册完成后就删除
解决思路
然后网上搜了下,原来我这样写的方法叫悲观锁:
总是假设最坏的情况,每次取数据时都认为其他线程会修改,所以都会加(悲观)锁。一旦加锁,不同线程同时执行时,只能有一个线程执行,其他的线程在入口处等待,直到锁被释放。涨知识了,这方面的知识看来还得再补补…
```php
//此处省略部分代码
$RDS = new Redis();
$RDS->connect(‘127.0.0.1’);
//1. 判断用户名和密码是否合规
//2. 检查该用户名是否正在注册中,防止一个用户名多次用户注册
if ($RDS->sIsMember(“nickname”, $username)) {
die(‘对不起,你输入的用户名正由别人注册中,请稍后再试!’);
}
//3. 判断该用户名是否被注册
//4. 添加“用户名注册锁”
$RDS->sAdd(“nickname”, $username);
//5. 插入数据库
//6. 删除该用户名锁
$RDS->sRem(“nickname”, $username);
//7. 判断是否注册(插入数据库)成功
```