PDO mysql: Jak sprawdzić, czy wstawienie się powiodło


96

Używam PDO do wstawienia rekordu (mysql i php)

$stmt->bindParam(':field1', $field1, PDO::PARAM_STR);
$stmt->bindParam(':field2', $field2, PDO::PARAM_STR);
$stmt->execute();

Czy istnieje sposób, aby dowiedzieć się, czy wstawiono go pomyślnie, na przykład jeśli rekord nie został wstawiony, ponieważ był duplikatem?

Edycja: oczywiście mogę przeglądać bazę danych, ale mam na myśli automatyczne sprzężenie zwrotne.

Odpowiedzi:


141

PDOStatement->execute()zwraca prawdę po sukcesie. Istnieje również PDOStatement->errorCode()możliwość sprawdzenia błędów.


1
Jak patrzysz na wartość execute ()?
Mallow

29
Koniec z tym, $ value = $ stmt-> execute (); if ($ value) {// true} else {// false}
Ólafur Waage

23
Albo możesz po prostu zrobićif ($stmt->execute()) { //true }
Gavin

2
Czy PDOStatement->execute()i są PDOStatement->errorCode()ze sobą całkowicie zgodne? Czy są jakieś okoliczności, w których PDOStatement->errorCode()coś ma, ale PDOStatement->execute()zwraca prawdę? Albo kiedy PDOStatement->execute()zwraca fałsz, ale PDOStatement->errorCode()nic nie ma?
datasn.io

2
Ale INSERT IGNORE również powrócić prawda nawet jeśli nie został wstawiony nowy rekord
Koffeehaus

26

Biorąc pod uwagę, że najbardziej zalecanym trybem błędu dla PDO jest ERRMODE_EXCEPTION, żadna bezpośrednia execute()weryfikacja wyników nigdy nie zadziała . Ponieważ wykonanie kodu nie osiągnie nawet stanu oferowanego w innych odpowiedziach.

Tak więc istnieją trzy możliwe scenariusze obsługi wyniku wykonania zapytania w PDO:

  1. Aby stwierdzić sukces, nie jest potrzebna weryfikacja. Po prostu trzymaj się swojego programu.
  2. Aby poradzić sobie z nieoczekiwanym błędem, trzymaj się tego samego - nie jest potrzebny żaden kod obsługi natychmiastowej. Wyjątek zostanie zgłoszony w przypadku błędu bazy danych i pojawi się w programie obsługi błędów dla całej witryny, co ostatecznie doprowadzi do typowej strony błędu 500.
  3. Aby obsłużyć oczekiwany błąd, na przykład zduplikowany klucz podstawowy, i jeśli masz określony scenariusz obsługi tego konkretnego błędu, użyj try..catchoperatora.

Dla zwykłego użytkownika PHP brzmi to trochę obco - jak to nie weryfikować bezpośredniego wyniku operacji? - ale tak właśnie działają wyjątki - sprawdzasz błąd gdzie indziej. Raz na zawsze. Niezwykle wygodny.

A więc w skrócie: w zwykłym kodzie nie potrzebujesz żadnej obsługi błędów. Po prostu zachowaj swój kod tak, jak jest:

$stmt->bindParam(':field1', $field1, PDO::PARAM_STR);
$stmt->bindParam(':field2', $field2, PDO::PARAM_STR);
$stmt->execute();
echo "Success!"; // whatever

Jeśli się powiedzie, powie ci to, po błędzie pokaże ci zwykłą stronę błędu, którą twoja aplikacja wyświetla na taką okazję.

Tylko w przypadku, gdy masz scenariusz obsługi inny niż tylko zgłoszenie błędu, umieść instrukcję insert w try..catchoperatorze, sprawdź, czy to był oczekiwany błąd i obsłuż go; lub - jeśli błąd był inny - wyślij ponownie wyjątek, aby umożliwić obsługę błędu w całej witrynie w zwykły sposób. Poniżej znajduje się przykładowy kod z mojego artykułu o obsłudze błędów w PDO :

try {
     $pdo->prepare("INSERT INTO users VALUES (NULL,?,?,?,?)")->execute($data);
} catch (PDOException $e) {
    if ($e->getCode() == 1062) {
        // Take some action if there is a key constraint violation, i.e. duplicate name
    } else {
        throw $e;
    }
}
echo "Success!";

W powyższym kodzie sprawdzamy, czy konkretny błąd wykonuje jakąś akcję i ponownie zgłaszamy wyjątek dla dowolnego innego błędu (na przykład nie ma takiej tabeli), który zostanie zgłoszony programistowi.

Znowu - tylko po to, aby powiedzieć użytkownikowi coś w rodzaju „Twoja wstawka się powiodła”, żaden warunek nie jest nigdy potrzebny.


Co oznacza „sukces”? Czy to oznacza, że ​​wstawiono nowy wiersz, czy to oznacza, że ​​nie ma żadnego błędu?
Martin AJ

W przypadku zapytania INSERT jest prawie tak samo.
Twój zdrowy rozsądek

Masz rację ... Czy możesz mi powiedzieć, co z query()funkcją? Czy query()zamiast tego mogę użyć try-catch prepared()->execute()?
Martin AJ

3
W pierwszej kolejności nigdy nie należy używać zapytania () do wstawiania. Wstaw oznacza, że ​​jest wejście, a wejście oznacza, że ​​powinno być przygotowane.
Twój zdrowy rozsądek

1
Używając MySQL, musiałem sprawdzić, czy $ e-> errorInfo [1] == 1062, aby sprawdzić, czy wstawianie nie powiodło się, ponieważ $ e-> getCode () to zawsze 23000.
tronman


9

Jeśli zapytanie aktualizujące zostanie wykonane z wartościami pasującymi do bieżącego rekordu bazy danych $stmt->rowCount(), zwróci wynik, 0jeśli nie dotyczy to żadnych wierszy. Jeśli masz if( rowCount() == 1 )do przetestowania powodzenie, pomyślisz, że aktualizacja nie powiodła się, ale nie zawiodła, ale wartości były już w bazie danych, więc nic się nie zmieni.

$stmt->execute();
if( $stmt ) return "success";

To nie zadziałało, gdy próbowałem zaktualizować rekord z unikalnym polem klucza, które zostało naruszone. Zapytanie zwróciło sukces, ale inne zapytanie zwróciło starą wartość pola.


3
Jeśli POTRZEBUJESZ wstawienia rekordu, najlepszym sposobem jest sprawdzenie w ten sposób ............................. ..... .................. if($stmt->execute() && ($stmt->rowCount()>0))
jave.web

4

Możesz przetestować liczbę wierszy

    $sqlStatement->execute( ...);
    if ($sqlStatement->rowCount() > 0)
    {
        return true;
    }

Odniesienie do dokumentacji jest zawsze pomocne @YourCommonSense. Mówi „to zachowanie nie jest gwarantowane dla wszystkich baz danych i nie powinno się na nim polegać w przypadku aplikacji przenośnych”, ale jest ograniczone do wyboru po pierwsze, a po drugie obsługiwane przez mysql, który jest tematem tego postu.
crafter

po prostu wpisz "pdo rowcount" w pasku adresu przeglądarki i kliknij pierwszy link. potrzeba mniej wpisywania niż komentarza
Your Common Sense

1
@crafter Correct. Mówi, że rowCount () może być nierealne dla SELECTzapytań (a nawet tam dokumentacja mówi o wielu zapytaniach). To nic nie mówi na temat DELETE, INSERTlub UPDATE, co wydaje się być w porządku do pracy (pytanie było o INSERTzapytaniu). Jednak jestem nowy w PDO i jeśli się mylę i ktoś ma inne referencje, napisz je tutaj. Jestem zainteresowany, aby sprawdzić, czy te 3 polecenia powyżej mają rzeczywiste wady.
StanE

1

Użyj identyfikatora jako klucza podstawowego z automatyczną inkrementacją

$stmt->execute();
$insertid = $conn->lastInsertId();

przyrostowy identyfikator jest zawsze większy od zera nawet na pierwszym rekordzie, co oznacza, że ​​zawsze zwraca prawdziwą wartość dla id coz większa niż zero oznacza prawdę w PHP

if ($insertid)
   echo "record inserted successfully";
else
   echo "record insertion failed";

A jeśli nie potrzebuję pola automatycznie zwiększanego w mojej tabeli?
Your Common Sense

Kto nie wie? ty? z interfejsem API RESTFul, który jest używany tak szeroko, identyfikator automatycznego zwiększania jest jak obowiązkowy.
skoczek rbk

Dlaczego ktoś nie miałby mieć podstawowej i automatycznej inkrementacji ani żadnej innej kolumny sekwencji? Jeśli wymagana jest metoda weryfikacji, dodaj dowolną kolejną kolumnę. Jeśli to rozwiązanie nie jest dla Ciebie, nie dodawaj go. Dla mnie to dobra opcja, zawsze używam jakiejś kolumny sekwencyjnej i automatycznej, więc zawsze mogę sprawdzić, czy moje zapytanie zakończyło się pomyślnie.
Samuel Ramzan

0

PDOStatement-> execute () może zgłosić wyjątek

więc możesz zrobić

try
{
PDOStatement->execute();
//record inserted
}
catch(Exception $e)
{
//Some error occured. (i.e. violation of constraints)
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.