PDO transaction prepared statements
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:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?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();
}
}
?>
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
Welke storage engine gebruik je? Niet elke storage engine ondersteunt transactions (MyISAM, de standard, in elk geval niet).
Dan kan ik lang blijven zoeken als het daarop niet werkt.
Welke raad je wel aan te gebruiken?
Ik heb de volgende keuzes
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<select name="new_tbl_type">
<option value="MRG_MYISAM" title="Collection of identical MyISAM tables">
MRG_MYISAM
</option>
<option value="BLACKHOLE" title="/dev/null storage engine (anything you write to it disappears)">
BLACKHOLE
</option>
<option value="CSV" title="CSV storage engine">
CSV
</option>
<option value="MEMORY" title="Hash based, stored in memory, useful for temporary tables">
MEMORY
</option>
<option value="ARCHIVE" title="Archive storage engine">
ARCHIVE
</option>
<option value="MyISAM" title="Default engine as of MySQL 3.23 with great performance" selected="selected">
MyISAM
</option>
</select>
<option value="MRG_MYISAM" title="Collection of identical MyISAM tables">
MRG_MYISAM
</option>
<option value="BLACKHOLE" title="/dev/null storage engine (anything you write to it disappears)">
BLACKHOLE
</option>
<option value="CSV" title="CSV storage engine">
CSV
</option>
<option value="MEMORY" title="Hash based, stored in memory, useful for temporary tables">
MEMORY
</option>
<option value="ARCHIVE" title="Archive storage engine">
ARCHIVE
</option>
<option value="MyISAM" title="Default engine as of MySQL 3.23 with great performance" selected="selected">
MyISAM
</option>
</select>
Gewijzigd op 23/04/2014 14:49:04 door Michael -
Hier een lijstje met engines van Wikipedia: http://en.wikipedia.org/wiki/Comparison_of_MySQL_database_engines
Misschien eens contact opnemen met m'n hosting of hun wat voor me willen/kunnen doen.
Bedankt voor je reactie in ieder geval. Ik weet nu in ieder geval waar het probleem ligt.
Toevoeging op 23/04/2014 15:51:54:
Ik krijg als antwoord van de support om de 'MariaDB database (BETA)' te gebruiken die wel InnoDB ondersteund.
Wat vinden jullie van MariaDB en is het verschil met MySQL erg groot?
http://en.wikipedia.org/wiki/MariaDB ) leert dat het wel goed zou moeten zitten. Ontwikkeld door hetzelfde team als dat MySQL heeft ontwikkeld. Ik kan alleen zo snel niet vinden welke php mogelijkheden er zijn, maar iets zegt me dat je gewoon PDO moet kunnen gebruiken.
Geen ervaring mee, maar een snelle blik op de Wikipedia pagina ( Gewijzigd op 23/04/2014 16:03:24 door Erwin H
Ik ga morgen verder kijken hoe ik kan overschakelen.
Quote:
The goal for Maria-DB is to be a drop-in replacement for MySQL – with more features and better performance.
MariaDB is based on the corresponding version of MySQL, if one exists. For example, MariaDB 5.1.53 is based on MySQL 5.1.53, with some added bug fixes, additional storage engines, new features, and performance improvements. Versions of MariaDB that do not have an equivalently numbered version of MySQL (e.g., MariaDB 5.2.4) contain major new features the developers felt warranted a new version number. When comparing the two here, I’ll focus on the additional features of MariaDB.
MariaDB is based on the corresponding version of MySQL, if one exists. For example, MariaDB 5.1.53 is based on MySQL 5.1.53, with some added bug fixes, additional storage engines, new features, and performance improvements. Versions of MariaDB that do not have an equivalently numbered version of MySQL (e.g., MariaDB 5.2.4) contain major new features the developers felt warranted a new version number. When comparing the two here, I’ll focus on the additional features of MariaDB.
bron
Ik vind het wel typisch dat een hosting adviseert om MariaDb te gaan gebruiken omdat de MySQL versie die zij draaien geen InnoDB engine heeft. Welke versie is dat?
Waar Ger nog aardig "typisch" schrijft, zou ik "verontrustend" invullen.
Ger & Ward, ja bijzonder is t wel. Ik weet ook niet hoeveel werk het voor hun is om InnoDB op MySQL te installeren? Ze kunnen vast niet aan alle gebruikerswensen gehoor geven.
Ger, Welke versie MySQL? Waar kan ik dat vinden? In phpinfo() staat 'MySQL Client API version 5.5.35' en in phpmyadmin staat 'MySQL-client versie: 5.1.72'.
Edit:
Voor de MySQL is het versie 5.1.73
Voor MariaDB is de MySQL versie 5.5.36
Voor de MySQL is het versie 5.1.73
Voor MariaDB is de MySQL versie 5.5.36
Toevoeging op 23/04/2014 20:33:23:
Ik heb zojuist een database aangemaakt in MariaDB er hier de tabellen in geïnstalleerd.
Standaard staat deze engine wel op InnoDB en de rollback werkt! :)
Gewijzigd op 23/04/2014 20:15:26 door Michael -
Voor een zichzelf respecterende hosting provider zou dat op zijn minst 5.5 moeten zijn
Gewijzigd op 23/04/2014 21:31:10 door Ger van Steenderen
Om de engines te tonen gebruik je:
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
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...
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
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.
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.
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:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?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();
}
?>
$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.
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.
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.
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.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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();
}
?>
$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();
}
?>