[MySQL/PHP] – transakcje parametryzowanych zapytań mysql z użyciem instrukcji try catch

Transakcje są grupami instrukcji języka SQL, z punktu widzenia przetwarzania traktowane są jako jedna całość – Czyli jeśli coś po drodze zawiedzie – nic nam się nie zapisze do bazy.

Thank you for reading this post, don't forget to subscribe!

Dzisiejsze nasze zadanie będzie następujące.

Napiszemy skrypt, który będzie składał się z dwóch parametryzowanych zapytań. Pierwsze z nich będzie wstawiało nowe dane do tabeli ‘tabela_1’, (gdzie mamy id auto_increment), natomiast drugie również będzie dodawało nowy rekord tylko, że już do tabeli ‘tabela_2’ a w rekordzie będzie zapisywało miedzy innymi id z nowo wstawionego rekordu tabeli ‘tabela_1’. Dane to zapytań będą pochodziły z formularza (którego strukturę już sobie w tym kodzie pominąłem).

Trochę zamotałem – ale myślę, że każdy po analizie poniższego kodu zrozumie o co chodzi:).

Na początku należy pamiętać o połączeniu z bazą danych:

$mysqli = new mysqli("localhost", "my_user", "my_password", "world");

/* check connection */
if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
}

następnie odbieramy dane z formularza i otwieramy blok try catch w celu przeprowadzenia naszej transakcji:


//zapisujemy dane z formularza w przykładowych zmiennych. 
$name = htmlentities($_POST['name'],ENT_QUOTES);
$slug = htmlentities($_POST['slug'],ENT_QUOTES);
$parent_id = htmlentities($_POST['parent_id'],ENT_QUOTES);
$description = htmlentities($_POST['description'],ENT_QUOTES);
						
if($name=='' || $slug==''||$parent_id==''){
	$error="Pola : nazwa, uproszczona nazwa, Kategoria nadrzędna - muszą być uzupełnione! 
"; }else{ try{ /* ustawiamy autocommit na wylączony */ $mysqli->autocommit(FALSE); $stmt1 = $mysqli->prepare("INSERT INTO tabela_1 (name, slug) VALUES ( ?,?)"); $stmt1->bind_param('ss', $name, $slug); if ($stmt1->execute() == false) { throw new Exception('Zapytanie 1 się nie powiodło'); } //pobranie id nowo stworzonego rekordu tabeli_1 $last_id = $stmt1->insert_id; if($last_id=='' or !is_numeric($last_id)){ throw new Exception('Wynikł problem z id tabeli 1'); }else{ $stmt2 = $mysqli->prepare("INSERT INTO tabela_2 (term_id, taxonomy, description, parent) VALUES ( ?,?,?,?)"); $taxonomy='category'; $stmt2->bind_param('issi', $last_id, $taxonomy, $description,$parent_id); if ($stmt2->execute() == false) { throw new Exception('Zapytanie 2 się nie powiodło'); } $stmt1->close(); $stmt2->close(); $mysqli->commit(); } }catch(Exception $e){ $mysqli->rollback(); echo $e->getMessage(); } }

I w ten oto prosty sposób zapewniamy sobie mechanizm transakcji dla wprowadzania danych z formularza do dwóch różnych tabel.

Dodam jeszcze kilka linijek wyjaśnienia:)

 htmlentities($_POST['name'],ENT_QUOTES); 

Funkcja htmlentities() konwertuje znaki specjalne na znaczniki HTML

 $mysqli->autocommit(FALSE);

Musimy pamiętać, iż każda wykonywana operacja w MySQL jest wykonywana w transakcji, to znaczy mniej więcej tyle, że każda pojedyncza operacja (SELECT, UPDATE, INSERT itp) jest wykonywana i automatycznie zakańczana. Wiec wpisując funkcję autocommit() z wartością FALSE wyłączamy na chwilę zatwierdzanie każdej operacji.

$stmt1 = $mysqli->prepare("INSERT INTO tabela_1 (name, slug) VALUES ( ?,?)");
$stmt1->bind_param('ss', $name, $slug);
	if ($stmt1->execute() == false) {
		throw new Exception('Zapytanie 1 się nie powiodło');
	}

Przygotowujemy zapytanie sql (funkcja prepare()), za pomocą bind_param() przekazujemy parametry do zapytania ( ‘ss’ – oznacza, że przekazujemy dwie zmienne typu string) następnie warunek z execute() wywołuje zapytanie i jeśli jest błąd to wyrzucamy wyjątek.
Oznacza to w skrócie tyle, że wykonanie ataku typu SQL INJECTION, nie jest już możliwe.

$mysqli->commit(); 

Jeśli nie było żadnych błędów po drodze – zatwierdzamy transakcję poprzez funkcję commit();

$mysqli->rollback(); 

i na końcu w sekcji catch wstawiamy funkcję rollback() która w przypadku wyrzucenia wyjątku / błędu – cofa wprowadzone dane.

Jeśli były by jeszcze jakieś niejasności, zapraszam do komentowania.
Pozdrawiam.