Allen,

Op de bekende zoekmachine kom ik genoeg voorbeelden tegen van prepared statements i.c.m. transactions.
Maar toch werkt bij mij de rollback niet. Een exception op de 2e tabel, terwijl de 1e wel is toegevoegd.

Kan iemand mij uitleggen wat er fout gaat? Dit is de eerste keer dat ik transactions wil gebruiken.

Ingekort voorbeeld:

<?php
try
{
	$db->beginTransaction();

	$sql = "
	INSERT
		INTO " . TABLE_PREFIX . "profile
		(
			naam
		)
		VALUES
		(
			:naam
		)
	";
	
	$stmt = $db->prepare($sql);
	
	$stmt->bindParam(':naam', $_POST['gegevens']['naam'], PDO::PARAM_STR);

	$stmt->execute();
	
	$profile_id = $db->lastInsertId();
	
	$sql = "
	INSERT
		INTO " . TABLE_PREFIX . "application
		(
			profile_id
		)
		VALUES
		(
			:profile_id
		)
	";
	
	$stmt = $db->prepare($sql);
	
	$stmt->bindParam(':profile_id', $profile_id, PDO::PARAM_INT);

	$stmt->execute();
	
	$db->commit();
}
catch(PDOException $e)
{
	if(isset($db))
	{
		$db->rollBack();
	}
}
?>


Bvd
Volgens mij kan je in PMA (ik gebruik dat bij voorkeur niet) boven aan de pagina zien welke server versie gebruikt wordt van MySQL
Voor een zichzelf respecterende hosting provider zou dat op zijn minst 5.5 moeten zijn
Je kunt de MySQL-versie ook controleren met:

SELECT VERSION();

Om de engines te tonen gebruik je:

SHOW ENGINES;

Ger van Steenderen op 23/04/2014 21:21:54

Volgens mij kan je in PMA (ik gebruik dat bij voorkeur niet) boven aan de pagina zien welke server versie gebruikt wordt van MySQL
Voor een zichzelf respecterende hosting provider zou dat op zijn minst 5.5 moeten zijn

Inderdaad, en als dat minimaal MySQL 5.5 is, dan wordt het alleen nog vreemder: vanaf versie 5.5 is InnoDB namelijk de standaard engine...
Ik had in een eerdere post al de versies en engines genoemd.
MySQL heeft versie 5.1.73
MariaDB heeft MySQL versie 5.5.36 (Standaard InnoDB inderdaad).
Hoe heb je MyISAM altijd gebruikt dan i.c.m. relaties? :o
Michael, kom je er nu uit met de prepared statements? Of heb je nog wat hulp nodig?

Ik zou zelf twee kleinigheden veranderen:

• de transactie pas starten na het klaarzetten van de prepared statement, dus voor de eerste execute();

• van het tweede prepared statement een gewone query maken, want je gebruikt hier de last insert ID rechtstreeks uit de database.
>> Hoe heb je MyISAM altijd gebruikt dan i.c.m. relaties? :o
Wat bedoel je? JOINS? Dat werkt gewoon.

Ward, Ja de rollback werkt nu.
Dus regel 4 kan beter op regel 21.
Waarom is de tweede niet goed dan? (en dus ook de 3e,4e,5e,6e..) Ik zou wel graag de prepared statements behouden i.v.m. security.
De tweede mag ook een prepared statement zijn hoor, alleen gebruik je in dit voorbeeld uitsluitend de last insert ID rechtstreeks uit de database. Er komt hier niets mogelijk kwaadaardigs van buiten naar binnen, dus voegt een prepared statement weinig toe.

Aangezien de database pas bij de execute() daadwerkelijk wordt gewijzigd, kun je het starten van de transactie uitstellen totdat alle voorbereidingen afgerond zijn (dus het "prepared" van een prepared statement rond is). Schematisch is dat zoiets:


<?php
$stmt_one   = $dbh->prepare('...');
$stmt_two   = $dbh->prepare('...');
$stmt_three = $dbh->prepare('...');

$stmt_one->bindParam('...');
$stmt_two->bindParam('...');
$stmt_three->bindParam('...');

$dbh->beginTransaction();

try {

    $stmt_one->execute();
    $stmt_two->execute();
    $stmt_three->execute();

    $dbh->commit();

} catch (PDOException $e) {

    $dbh->rollBack();

}
?>


Uiteraard kun je ook in het eerste deel nog foutafhandeling toevoegen, alleen hoeft de rollBack() eigenlijk de drie keer execute() terug te rollen.

Bedankt voor de uitleg!
Wat doe je nu met de last insert id dan? Dat laat je niet zien. Wanneer is die beschikbaar en kan ik die toevoegen in de tabellen.

Zoals ik het nu heb wordt er al een id aangemaakt, auto_increment, en vervolgens weer verwijdert.
Wat ik dus krijg als er een fout in de 2e,3e,4e... tabel zit, dat alles wordt terug gedraaid, en ik weer wat toevoeg, dat hij dan een id overslaat. Heb je dat met jouw voorbeeld nog steeds?
Op zich vind het niet heel erg, dan kan ik ook zien wanneer er wat fout is gegaan, maar vroeg het me af.
>> Wat doe je nu met de last insert id dan?

Daarvoor moet je dan wel een extra query of prepared statement tussenvoegen. Je krijgt dan inderdaad een andere volgorde dan mijn (algemene) voorbeeld, want de last insert ID is pas na het uitvoeren van de voorafgaande prepared statement bekend.
Mweh... dan kan ik jouw voorbeeld dus al niet toepassen.
Hoe doe je dat zelf dan om tabellen te koppelen? Ik moet toch weten welke bij welke horen. Dat kan ik niet achteraf nog gaan uitzoeken lijkt me.

Maakt ie in jouw voorbeeld wel een id aan en verwijdert deze weer? Dus de a_i verhoogt met 1?
In onderstaande zou dat sowieso wel weer gebeuren.

<?php
$stmt_one = $dbh->prepare('...');
$stmt_one->bindParam('...');
$stmt_one->execute();
$profile_id = $dbh->lastInsertId();

$stmt_two = $dbh->prepare('...');
$stmt_three = $dbh->prepare('...');

$stmt_two->bindParam(':profile_id', $profile_id, PDO::PARAM_INT);
$stmt_three->bindParam(':profile_id', $profile_id, PDO::PARAM_INT);

$dbh->beginTransaction();

try {
$stmt_two->execute();
$stmt_three->execute();

$dbh->commit();

} catch (PDOException $e) {

$dbh->rollBack();

}
?>

Reageren