-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathconcepts.xml
198 lines (170 loc) · 7.07 KB
/
concepts.xml
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: 968c2bc60de3e93d7f38be0b9d2d1b9685a16ea7 Maintainer: samesch Status: ready -->
<!-- Reviewed: no -->
<chapter xml:id="mysqlinfo.concepts" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Konzepte</title>
<para>
Diese Konzepte gelten speziell für die MySQL-Treiber für PHP.
</para>
<section xml:id="mysqlinfo.concepts.buffering">
<title>Gepufferte und ungepufferte Abfragen</title>
<para>
Abfragen werden standardmäßig im gepufferten Modus ausgeführt. Das
bedeutet, dass die Abfrageergebnisse sofort vom MySQL-Server an PHP
übertragen werden und dann im Speicher des PHP-Prozesses gehalten werden.
Dies ermöglicht weitere Aktionen wie die Anzahl der Zeilen zu zählen und
den aktuellen Ergebniszeiger zu verschieben (zu suchen). Außerdem ist es
möglich, weitere Abfragen über dieselbe Verbindung durchzuführen, während
die Ergebnismenge verarbeitet wird. Der Nachteil des gepufferten Modus ist,
dass größere Ergebnismengen viel Speicherplatz benötigen können. Der
Speicher bleibt so lange belegt, bis alle Verweise auf die Ergebnismenge
aufgehoben sind oder die Ergebnismenge explizit freigegeben wurde, was
spätestens beim Beenden der Abfrage automatisch geschieht. Weil beim
gepufferten Modus die gesamte Ergebnismenge auf einmal gespeichert wird,
wird auch der Ausdruck "store result" (Ergebnis speichern) verwendet.
</para>
<note>
<para>
Wenn die Bibliothek libmysqlclient verwendet wird, wird der für eine
Ergebnismenge verwendete Speicher nicht zum PHP-Speicherlimit gezählt, es
sei denn, die Daten werden in PHP-Variablen abgerufen. Mit mysqlnd wird
die gesamte Ergebnismenge in den Speicher mit eingerechnet.
</para>
</note>
<para>
Ungepufferte MySQL-Abfragen führen die Abfrage aus und warten dann darauf,
dass die Daten vom MySQL-Server abgerufen werden. Dadurch wird zwar weniger
Speicher von PHP verwendet, aber die Last auf dem Server kann steigen.
Solange nicht die gesamte Ergebnismenge vom Server abgerufen wurde, können
keine weiteren Abfragen über dieselbe Verbindung gesendet werden.
Ungepufferte Abfragen können auch als "use result" (Ergebnis verwenden)
bezeichnet werden. Nachdem alle Zeilen der Ergebnismenge abgerufen wurden,
ist die Ergebnismenge weg, und kann nicht mehr durchlaufen werden.
</para>
<para>
Aufgrund dieser Merkmale sollten ungepufferte Abfragen nur verwendet
werden, wenn eine große Ergebnismenge erwartet wird, die sequentiell
verarbeitet werden soll. Ungepufferte Abfragen weisen eine Reihe von
Fallstricken auf, die ihre Verwendung erschweren, &zb; ist die Anzahl der
Zeilen in der Ergebnismenge erst bekannt, nachdem die letzte Zeile
abgerufen wurde. Gepufferte Abfragen sind die einfachere und flexiblere
Lösung, um Ergebnismengen zu verarbeiten.
</para>
<para>
Da standardmäßig gepufferte Abfragen verwendet werden, zeigen die folgenden
Beispiele, wie ungepufferte Abfragen mit der jeweiligen API ausgeführt
werden.
</para>
<example>
<title>Beispiel für ungepufferte Abfragen: mysqli</title>
<programlisting role="php">
<![CDATA[
<?php
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
$unbufferedResult = $mysqli->query("SELECT Name FROM City", MYSQLI_USE_RESULT);
foreach ($unbufferedResult as $row) {
echo $row['Name'] . PHP_EOL;
}
?>
]]>
</programlisting>
</example>
<example>
<title>Beispiel für ungepufferte Abfragen: pdo_mysql</title>
<programlisting role="php">
<![CDATA[
<?php
$pdo = new PDO("mysql:host=localhost;dbname=world", 'my_user', 'my_password');
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$unbufferedResult = $pdo->query("SELECT Name FROM City");
foreach ($unbufferedResult as $row) {
echo $row['Name'] . PHP_EOL;
}
?>
]]>
</programlisting>
</example>
</section>
<section xml:id="mysqlinfo.concepts.charset">
<title>Zeichensätze</title>
<para>
Idealerweise sollte der richtige Zeichensatz auf Serverebene eingestellt
werden. Dies wird im Abschnitt
<link xlink:href="&url.mysql.charsets.config;">Character Set Configuration</link>
des Handbuchs zum MySQL-Server beschrieben. Alternativ dazu bietet jede
MySQL-API eine Methode, um den Zeichensatz zur Laufzeit zu setzen.
</para>
<caution>
<title>Der Zeichensatz und die Maskierung von Zeichen</title>
<para>
Da sich der Zeichensatz auf jede Aktion auswirkt und auch Auswirkungen auf
die Sicherheit hat, sollte er bekannt und definiert sein. Zum Beispiel
orientiert sich der Mechanismus für das Maskieren (&zb;
<function>mysqli_real_escape_string</function> bei mysqli und
<methodname>PDO::quote</methodname> bei PDO_MySQL) an dieser Einstellung.
Es ist wichtig zu wissen, dass diese Funktionen nicht den Zeichensatz
verwenden, der für eine Abfrage definiert ist, sodass &zb; Folgendes
keinen Einfluss auf sie hat:
</para>
</caution>
<example>
<title>Probleme beim Einstellen des Zeichensatzes mit SQL</title>
<programlisting role="php">
<![CDATA[
<?php
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
// Wirkt sich NICHT auf $mysqli->real_escape_string(); aus
$mysqli->query("SET NAMES utf8mb4");
// Wirkt sich NICHT auf $mysqli->real_escape_string(); aus
$mysqli->query("SET CHARACTER SET utf8mb4");
// Allerdings wirkt sich das auf $mysqli->real_escape_string(); aus
$mysqli->set_charset('utf8mb4');
// Aber das wirkt sich NICHT aus (UTF-8 vs. utf8mb4) - hier keine Bindestriche verwenden
$mysqli->set_charset('UTF-8');
?>
]]>
</programlisting>
</example>
<para>
Die folgenden Beispiele zeigen, wie der Zeichensatz mit der jeweiligen API
korrekt zur Laufzeit geändert werden kann.
</para>
<note>
<title>Möglicher Fehler mit UTF-8</title>
<para>
Da die Namen von Zeichensätzen in MySQL keine Bindestriche enthalten, muss
in MySQL die Zeichenkette "utf8" verwendet werden, um den Zeichensatz auf
UTF-8 zu setzen (bis zu 3 Byte UTF-8 Unicode Encoding). Die Zeichenkette
"UTF-8" ist dagegen ungültig, weshalb der Zeichensatz mit "UTF-8" nicht
geändert werden kann und ein Fehler ausgegeben wird.
</para>
</note>
<example>
<title>Beispiel für das Einstellen des Zeichensatzes: mysqli</title>
<programlisting role="php">
<![CDATA[
<?php
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
echo 'Der ursprüngliche Zeichensatz: ' . $mysqli->character_set_name() . "\n";
if (!$mysqli->set_charset('utf8mb4')) {
printf("Fehler beim Laden des Zeichensatzes utf8mb4: %s\n", $mysqli->error);
exit;
}
echo 'Der aktuelle Zeichensatz: ' . $mysqli->character_set_name() . "\n";
?>
]]>
</programlisting>
</example>
<example>
<title>Beispiel für das Einstellen des Zeichensatzes: <link linkend="ref.pdo-mysql.connection">pdo_mysql</link></title>
<programlisting role="php">
<![CDATA[
<?php
$pdo = new PDO("mysql:host=localhost;dbname=world;charset=utf8mb4", 'my_user', 'my_pass');
?>
]]>
</programlisting>
</example>
</section>
</chapter>