programing

중복 항목 확인 vs PDO errorInfo 결과 사용

iphone6s 2023. 8. 25. 23:24
반응형

중복 항목 확인 vs PDO errorInfo 결과 사용

고유한 것으로 정의된 전자 메일 주소 필드가 있는 MySQL 테이블이 있습니다.이 예에서는 사용자가 표에 전자 메일 주소를 삽입할 수 있도록 허용하는 것이 양식의 전부라고 가정해 보겠습니다.

전자 메일 필드는 고유하므로 동일한 전자 메일을 두 번 입력하려고 하면 쿼리가 실패합니다.두 시나리오 간의 절충점이 궁금합니다.

실행 빨리달SELECT문을 열 수 있습니다.를 반환할 경우 , INSERT진술.

을 합니다.INSERT 중복된 항목 하기 ", "는 "입니다.

// snippet uses PDO
if (!$prep->execute($values))
{
    $err = $prep->errorInfo();
    if (isset($err[1]))
    {
        // 1062 - Duplicate entry
        if ($err[1] == 1062)
            echo 'This email already exists.';
    }
}

또한 중복 항목이 최소화되어야 함을 의미하는 정상적인 사용을 가정하십시오.따라서 첫 번째 시나리오에서는 모든 삽입에 대해 추가 쿼리를 실행해야 하는 오버헤드가 있는 반면 두 번째 시나리오에서는 오류 처리에 의존합니다.

그리고 코딩 스타일에 대한 생각도 궁금합니다.내 심장은 '방어적인 프로그래머가 되어라!삽입하기 전에 데이터를 확인하십시오!'라고 말하는 반면, 제 뇌는 '흠, MySQL이 데이터를 확인하도록 하는 것이 더 나을 수도 있습니다.'라고 말합니다.

편집 - 이 질문은 "어떻게 해야 하나"가 아니라 "왜 특정한 방법으로 해야 하나"라는 질문입니다.제가 포함한 작은 코드 조각은 효과가 있지만, 제가 궁금한 것은 문제를 해결하는 가장 좋은 방법입니다.

시도 캐치 블록을 사용하여 이를 실행할 수 있습니다.

try {
   $prep->execute($values);
   // do other things if successfully inserted
} catch (PDOException $e) {
   if ($e->errorInfo[1] == 1062) {
      // duplicate entry, do something else
   } else {
      // an error other than duplicate entry occurred
   }
}

"INSERT IGNORE" 및 "INSERT..."와 같은 대안도 찾아볼 수 있습니다.중복 키 업데이트 시" - MySQL에 고유하며 PDO를 사용하는 휴대성에 위배된다고 생각합니다.

편집: 당신의 질문에 좀 더 공식적으로 대답하자면, 나에게, 완전하게 사용되는 솔루션 #1(방어적 프로그래머)은 애초에 고유한 제약의 요점을 효과적으로 제거합니다.그래서 나는 MySQL이 데이터 확인을 맡도록 하는 당신의 생각에 동의합니다.

INSERT상태를 확인하는 것이 더 나은 접근 방식이어야 합니다.와 함께SELECT+INSERT당신은 다른 스레드가 같은 값을 삽입하도록 할 수 있습니다.SELECT 리고그고.INSERT즉, 두 문장을 테이블 잠금 장치로 묶어야 합니다.

코딩에서 너무 많은 방어의 측면에서 실수하기 쉽습니다.Python은 "허락을 구하는 것보다 용서를 구하는 것이 더 쉽다"는 속담을 가지고 있으며, 이 철학은 실제로 Python만의 것이 아닙니다.

AUTO_INCREMENT 열이 있고 InnoDB를 사용하는 경우, 실패한 INSERT는 새 행이 추가되지 않더라도 "다음 자동 ID" 값을 증가시킵니다.예를 들어 INSERT ...에 대한 설명서를 참조하십시오. InnoDB에서 중복 키 및 AUTO_INCREMENT 처리 시.이로 인해 AUTO_INCREMENT ID에 공백이 발생할 수 있으며, 이는 ID가 부족할 수 있다고 생각하는 경우 문제가 될 수 있습니다.

따라서 이미 존재하는 행을 삽입하는 것이 일반적이며 AUTO_INCREMENT ID에 공백이 생기지 않도록 하려면 사전 검사와 예외 처리를 모두 수행할 수 있습니다.

$already_exists = false;
$stmt = $pdo->prepare("SELECT id FROM emails WHERE email = :email");
$stmt->execute(array(':email' => $email));
if ($stmt->rowCount() > 0) {
    $already_exists = true;
}
else {
    try {
        $stmt = $pdo->prepare("INSERT INTO emails (email) VALUES (:email)");
        $stmt->execute(array(':email' => $email));
    } catch (PDOException $e) {
        if ($e->errorInfo[1] == 1062) {
            $already_exists = true;
        } else {
            throw $e;
        }
    }
}

첫 번째 쿼리는 이미 존재하는 전자 메일을 확실히 알고 있는 경우 전자 메일을 삽입하지 않도록 합니다.두 번째 쿼리는 전자 메일이 아직 존재하지 않는 것 같으면 전자 메일을 삽입하려고 시도합니다.가능성이 낮은 경합 조건(위의 스니펫을 병렬로 실행하는 여러 클라이언트 또는 스레드)의 경우 중복이 여전히 발생할 수 있으므로 두 번째 쿼리에서 예외를 확인해야 합니다.

이 접근 방식은 코드를 강력하게 만드는 동시에 희귀한 레이스 조건을 제외하고는 AUTO_INCREMENT ID에 공백을 만들지 않습니다.또한 새 전자 메일을 삽입하는 것보다 기존 전자 메일을 삽입하는 것이 더 일반적인 경우 가장 빠른 방법입니다.기존 전자 메일을 삽입하려고 시도하는 경우가 드물고 AUTO_INCREMENT ID의 공백이 신경 쓰이지 않는 경우에는 사전 검사가 필요하지 않습니다.

더 간단한 방법은 오류 코드를 중복 상태 코드 배열과 비교하여 확인하는 것입니다.그렇게 하면 PDO가 반환하는 것에 대해 걱정할 필요가 없습니다.

$MYSQL_DUPLICATE_CODES=array(1062,23000);
try {
   $prep->execute($values);
   // do other things if successfully inserted
} catch (PDOException $e) {
   if (in_array($e->getCode(),$MYSQL_DUPLICATE_CODES)) {
      // duplicate entry, do something else
   } else {
      // an error other than duplicate entry occurred
   }
}

감사합니다! :-)

코드를 확인하는 대신, 기본 키 중복 항목을 캡처하기 위해 다음과 같은 캐치 블록을 사용했습니다. 오류 코드는 다음과 같습니다.1062 Duplicate entry

catch (PDOException $e) {

  if(str_contains($e, '1062 Duplicate entry')) {
       header("Location: login.php");
  }
die("Error inserting user details into database: " .  $e->getMessage());

}

언급URL : https://stackoverflow.com/questions/10774943/check-for-duplicate-entry-vs-use-pdo-errorinfo-result

반응형