5

私は学生で、ソフトウェアを書くのはこれが初めてです。これは LAMP スタック上の Web アプリケーションであり、その Web アプリケーションの一部として、新しいユーザーを作成するときにデータベースと対話する次の関数を作成しました。

public function CreateUser($username, $password, $email){
  global $DBHandler, $SQLStatement;
  $SQLStatement = $DBHandler->prepare("SELECT id FROM users WHERE username = :username AND verified > 0");
  $SQLStatement->bindParam(':username', $username);
  $SQLStatement->execute();
  $check = $SQLStatement->fetch();
  if ($check['id']){
    return 2;
  }else{
    $SQLStatement = $DBHandler->prepare("SELECT id FROM users WHERE email = :email AND verified > 0");
    $SQLStatement->bindParam(':email', $email);
    $SQLStatement->execute();
    $check = $SQLStatement->fetch();
    if ($check['id']){
      return 3;
    }else{
      /* Edited out code that generates a random verification code, a random salt, and hashes the password. */
      $SQLStatement = $DBHandler->prepare("INSERT INTO users (username, email, passwordhash, salt, verifycode) VALUES (:username, :email, :passwordhash, :salt, :verifycode)");
      $SQLStatement->bindParam(':username', $username);
      $SQLStatement->bindParam(':email', $email);
      $SQLStatement->bindParam(':passwordhash', $passwordhash);
      $SQLStatement->bindParam(':salt', $salt);
      $SQLStatement->bindParam(':verifycode', $verifycode);
      $SQLStatement->execute();
      return 1;
    }
  }
}

$DBHandler は、PHP データ オブジェクトとして別の場所で開始されます。

次の基本的な手順に従います。

  1. データベースにクエリを実行して、誰かが目的のユーザー名を持つアカウントを既に確認しているかどうかを確認します。
  2. ユーザー名が使用可能な場合は、別のクエリを実行し、電子メールに対して同じチェックを実行します。
  3. ユーザー名と電子メールの両方が利用可能な場合、検証コードを生成し、ソルトし、パスワードをハッシュし、3 番目のクエリを実行してすべてをデータベースに書き込み、1 (成功を意味します) を返します。

アカウントが確認されるまで (確認済み = '1')、ユーザー名と電子メールは予約されません。他の場所には、電子メールで送信された確認リンクをクリックすると、確認済みの列を「1」に変更するスクリプトがあります。

私の最初の質問はこれです:

人物 A はユーザー名 "Lorem" を提案しており、人物 B もユーザー名 "Lorem" を提案している未確認のアカウントを持っています。次の順序でクエリを実行することは可能ですか?

  1. ユーザー A のスクリプトは、ユーザー名 "Lorem" が確認済みのユーザーによって使用されていないと判断します
  2. ユーザー B のスクリプトは、ユーザー名「Lorem」で自分のアカウントを検証します
  3. ユーザー A のスクリプトは、ユーザー名「Lorem」で未確認のアカウントを作成します

私の2番目の質問は次のとおりです。

このスクリプトの 3 つのクエリを、PHP ではなく SQL で表現された同じ if/else ロジックを使用して 1 つのクエリに結合することは可能ですか? その場合、パフォーマンスが向上し、上記のシナリオが発生するのを防ぐことができますか?

4

1 に答える 1

2

insertより同時実行のソリューションについては、条件付きにすることができます。

insert  into users 
        (username, email, ...)
select  :username, :email, ...
where   not exists
        (
        select  *
        from    users
        where   verified > 0
                and (username = :username
                     or email = :email)
        )

これは MySQL ではまだ 100% 安全ではありませんが、実際には十分なはずです。

ユーザー作成における並行性の問題は贅沢な問題であることに注意してください。私はあなたが持っているもののような基本的なバージョンをセットアップし、あなたのウェブサイトのより興味深い側面に焦点を当てます!

于 2012-09-16T07:25:05.340 に答える