Symfony中避免重复Token存入数据库的功能实现求助
问题分析与修复方案
首先得指出你当前代码的核心问题:仓库层的getToken函数里,判断是否新增Token的逻辑完全写反了!你现在用empty($token)作为判断条件,但这个$token是前端传入的必填参数(控制器里已经做了校验),所以这个条件永远不会成立,导致永远不会执行新增操作;反过来如果传入空的$token才会新增,这显然和你的业务需求完全相悖。
正确的逻辑应该是:先查询数据库中是否存在该用户对应的目标Token,只有当查询结果为空(也就是这个Token不存在)时,才执行新增保存操作。
修复后的仓库层代码
public function getToken($user, $token) { // 先查询数据库,确认该用户的这个Token是否已存在 $tok = $this->getRepository() ->createQueryBuilder('pt') ->select('pt') ->where('pt.user = :user') ->andWhere('pt.token = :token') ->setParameter('user', $user) ->setParameter('token', $token) ->getQuery() ->getOneOrNullResult(); // 用getOneOrNullResult更贴合场景:要么返回单个实体,要么返回null // 如果查询结果为空,说明Token不存在,才新建并持久化 if(empty($tok)) { $tok = new Token(); $tok->setUser($user); $tok->setToken($token); $this->em->persist($tok); $this->em->flush(); } return $tok; }
控制器代码优化(可选)
可以在返回结果里带上Token的状态信息,方便前端确认操作结果:
public function getTokenAction() { $this->requirePostParams(['user', 'token']); $tokenEntity = $this->get('token')->getToken($this->getUser(), $this->data['token']); return $this->success([ 'token' => $tokenEntity->getToken(), 'is_existed' => isset($tokenEntity->getId()) // 通过是否有ID判断是已存在还是新增的 ]); }
关键额外优化:数据库层面加唯一约束
为了避免并发场景下的重复插入(比如同一时间两次请求提交同一个Token,代码层面的判断可能因为事务隔离性出现漏判),建议在token表的user_id和token字段上创建联合唯一索引。这样即使代码层面有遗漏,数据库也会直接报错拦截重复数据,从根源保证数据唯一性。
比如在Doctrine的Entity类里添加注解:
/** * @ORM\Entity * @ORM\Table( * uniqueConstraints={ * @ORM\UniqueConstraint(name="user_token_unique_idx", columns={"user_id", "token"}) * } * ) */ class Token { // ... 其他字段定义 }
然后执行Doctrine迁移命令更新数据库结构:
php bin/console doctrine:migrations:diff php bin/console doctrine:migrations:migrate
这样就能彻底解决重复Token的问题啦!
内容的提问来源于stack exchange,提问作者Филип Стојановић
相关产品推荐
相关产品推荐

