在mysql和php中处理双用户名

在mysql和php中处理双用户名,php,pdo,Php,Pdo,我正在编写自己的API实现。这个API的一个资源是/user,我可以将一个JSON字符串发布到这个API中,解析它并将它发送到一个UserService,它有一个addUser方法。现在很明显,我不能允许两个用户拥有相同的用户名。这就是我到目前为止必须做的 protected function handlePost() { $user = json_decode($this->getRequest()->getRequestData(), true); try {

我正在编写自己的API实现。这个API的一个资源是
/user
,我可以
一个
JSON
字符串发布到这个API中,解析它并将它发送到一个
UserService
,它有一个
addUser
方法。现在很明显,我不能允许两个用户拥有相同的用户名。这就是我到目前为止必须做的

protected function handlePost() {
    $user = json_decode($this->getRequest()->getRequestData(), true);

    try {
        $createdUserId = $this->userService->addUser(
            $user['username'],
            $user['password'],
            $user['typeId'],
            $user['companyId']
        );
    } catch (PDOException $e) {
        $this->getResponse()->setStatus(102);
    }

    if ($createdUserId)
        $this->getResponse()->setStatus(101);

    $this->getResponse()->sendResponse();
}
解析HTTP请求后调用此函数。如您所见,我在关联数组中获取
$user
对象。然后,我将这些值用作
$this->userService->addUser
方法的参数

这是
addUser()
方法:

public function addUser($username, $password, $type, $companyId) {
    $sth = $this->dbh->prepare('INSERT INTO app_user
                                (username, password, typeId, companyId)
                                VALUES (?, ?, ?, ?)');
    $userAdded = $sth->execute(array($username, md5($password), $type, $companyId));

    return ($userAdded)
        ? $this->dbh->lastInsertId()
        : null;
}
现在,如果
$sth->execute
由于某种原因失败,我将返回null(我知道状态代码101或102都不会返回)。但是,如果用户名已经存在,PDO将抛出一个异常,我在上面的
handlePost()方法中捕捉到了这个异常

当然,我的问题是,已经使用的用户名并不例外,不应该以这种方式处理,但我真的不知道该如何处理它

我必须能够区分被触发的唯一约束和被触发的其他约束(可能是并发问题),以便将适当的状态代码发送回API的使用者

一个显而易见的解决方案是检查用户名是否存在于一个单独的查询中,但出于显而易见的原因,我更愿意限制对数据库的调用


我怎样才能优雅地解决这个问题?如果我必须使用异常,是否有特定PDO异常的列表,这样我就不必使用通用的
PDOException

您是否足够关注性能(即最小化对数据库的查询),而不只是在尝试插入之前检查数据库中是否存在用户名?与试图捕获异常并根据上一次查询或类似查询所影响的行数确定是否确实存在异常相比,您可能会发现遵循此逻辑更容易


我还想补充一点,如果您想使其不成为异常,您可以在insert中添加重复的键逻辑。

如果您没有在PDO构造函数中使用ERRMODE_异常,PDO不应该发送完整性约束冲突的异常

在这种情况下,必须调用方法PDOStatement::errorCode()或PDOStatement::errorInfo()


以获取错误的详细信息,并查看它是违反完整性约束还是真正的问题

告诉我我是否理解正确-是否要检查数据库中是否存在不使用SQL的用户?您的代码说您正在编写API,但您的文本说您正在实现API。我糊涂了@Yehonatan不,不,我知道这是不可能的:p,我只是想知道是否有一种方法可以检查它,而不必使用异常来处理它,并将数据库的查询数量限制为最好的1。@Adnan,我正在编写消费者和提供者部分。两个选项,执行另一个查询,或者将用户名设置为唯一密钥并检测插入失败。我现在启用了ERRMODE\u异常模式,您认为不鼓励在生产中使用此模式吗?(这显然会迫使我改变我的方法)@pEkvo是的,对我来说,你不应该在prod中使用ERRMODE_异常:当发生重大错误时(比如db服务器无法访问),PDO会继续发送异常,但不会违反SQL约束,这在API中并不例外……理论上你是对的,但由于PHP具有无共享体系结构,你无法避免两个请求并行运行,试图插入相同的用户名,除非你创建一个全局机制在两个PHP请求之间锁定用户名。@BenjaminDubois,使用这种方法,我能不能把支票用户名和插入(如果还没有找到)放在一个事务中?@pEkvo yes!但您需要直接用SQL编写它,并用PHP调用它。@BenjaminDubois,好的,谢谢您的帮助。我将接受这个答案,因为这是我最想要的,但是在检查PDO文档后,您自己的答案也很有帮助,所以我将对它进行投票:)除非您谈论的是一个非常大的服务量,否则在同一时间使用同一个确切用户名的两个请求的机会可能非常小。在这种情况下,您是正确的,您可能首先不想进行两个单独的查询(因此我对性能的最初评论)。