Zeichencodierung/MySQL
Inhaltsverzeichnis
Kurzanleitung für Eilige
Wichtig ist zum einen, dass die Codierung der einzelnen String-Typ-Felder (CHAR, VARCHAR, TEXT, ENUM, SET) richtig eingestellt ist. Zum anderen sollte nach jedem Verbindungsaufbau dem MySQL-Server mitgeteilt werden, welche Codierung für die zu sendenden und empfangenen Daten verwendet werden soll. Diese beiden Einstellungen sorgen auf jeden Fall für Klarheit und einen reibungslosen Datenaustausch, egal was sonst noch für Konfigurationswerte auf dem MySQL-Server eingestellt sind.
Die Codierung der Felder legen Sie beim Erstellen der Tabelle fest. Sie kann auch nachträglich geändert werden, wobei die bereits enthaltenen Daten umcodiert werden. Voraussetzung für ein reibungsloses Umcodieren ist natürlich, dass die Daten in den Felder der bisher konfigurierten Codierung entsprechen.
Die Codierung auf der Verbindung zwischen Client und Server stellen Sie mit einer spezialisierten Funktion ein ‒ unter PHP beispielsweise mit mysql(i)_set_charset() ‒ oder mit einem „SET NAMES“-Statement.
Der Code im Beispiel beschränkt sich auf die erläuterte Funktionalität. Wenn Sie ihn übernehmen wollen, sollten Sie unbedingt auch eine Fehlerbehandlung vorsehen.
Was passiert, wenn MySQL und ein Client miteinander Daten austauschen
MySQL hat mit Version 4.1 sein Zeichencodierungskonzept stark erweitert. In der MySQL-Dokumentation beschäftigt sich das Kapitel Internationalization and Localization mit dem Thema. Doch vorab eine kleine Abschweifung.
Es gibt eine Menge Konfigurationsoptionen und -variablen [1]. Der Unterschied zwischen Option und Variable ist hier nicht weiter relevant. Einige dieser Variablen lassen sich jedenfalls individuell für die aktuelle Session (Verbindung) zwischen Client und Server umstellen. Es gibt dann neben dem globalen Wert den sessionspezifischen Wert. Man sieht das zum Beispiel im phpMyAdmin (abgekürzt PMA; ein recht beliebtes in PHP geschriebenes Verwaltungsprogramm für MySQL) unter "MySQL-System-Variablen anzeigen" / "Show MySQL system variables" auf der Startseite. Wenn keine Felder orange hinterlegt sind, kann man (ebenfalls auf der Startseite) mal den Wert "Zeichensatz / Kollation der MySQL-Verbindung" / "MySQL connection collation" umstellen. (Man macht sich dabei nichts Grundlegendes kaputt, denn das ist ein session-individueller Wert für den PMA.) Nun sollten einige Werte mit einer zweiten Zeile "(Globaler Wert)" / "(Global value)" zu sehen sein. Der obere Wert ist der session-individuelle. Nach dem Test sollte man "MySQL connection collation" wieder zurückstellen (Vergessen, was es war? utf8_general_ci passt meistens).
Für die Zeichensatz/-codierungsproblematik sind die Werte character_set_… relevant. Neben dem "Character Set" gibt es auch noch den Begriff "Collation", der oft in unmittelbarer Nähe zu "Character Set" zu finden ist. Collation hat aber zur Aufgabe Regeln für das Vergleichen von Zeichen (zum Sortieren beispielsweise) zu definieren. Für Probleme mit der Codierung kann man den Collation-Wert unberücksichtigt lassen. ‒ Übrigens, der Begriff Character Set (Zeichensatz) ist im Prinzip falsch, es müsste eigentlich Character Encoding (Zeichencodierung) heißen. Siehe dazu Zeichencodierung und geschriebene Sprache - Begrifflichkeiten.
Zurück zum eigentlichen Vorgang: Ein Client sendet ein SQL-Statement, von dem der MySQL-Server annimmt, es sei gemäß character_set_client codiert. (Innerhalb eines SQL-Statements können einzelne Werte anders codiert sein, wenn man sie besonders kennzeichnet. [2] Das braucht man im Normalfall aber nicht.) Das SQL-Statement wird umcodiert nach character_set_connection (außer den besonders gekennzeichneten Einzelwerten). Bis hier hin passiert das mit allen SQL-Statements, egal ob Daten gelesen oder geändert werden oder auch nicht. Die Ergebnisse, die in Richtung Client gesendet werden sollen, werden gemäß character_set_results codiert.
Die drei Variablen character_set_client, character_set_connection und character_set_results lassen sich mit der MySQL-C-API-Funktion mysql_set_character_set() (oder einem Pendant in einer sprachspezifischen API (PHP: mysql_set_charset()/mysqli_set_charset())) oder einem "SET NAMES"-Statement einstellen. (SET CHARACTER SET ändert die gleichen Variablen, jedoch in etwas anderer Form. In der Regel möchte man jedoch dieses Verhalten nicht.)
Soweit lässt sich das alles im Kapitel Character Set Support, speziell Connection Character Sets and Collations nachlesen. Nun fehlt aber noch der Teil wie Daten in und aus Feldern einer Tabelle geschrieben und gelesen werden. Dazu ist dem MySQL-Handbuch nicht explizit etwas zu entnehmen. Erfahrungen, gesammelt und bestätigt auch durch einige Experimente, besagen, dass die Daten noch einmal umcodiert werden, dieses Mal von character_set_connection in die Feldcodierung. Und für den Rückweg zum Client braucht es nur noch eine Umcodierung des Ergebnissets nach character_set_results.
Das waren eine Menge Umcodierungen. Idealerweise muss aber nichts umcodiert werden, wenn alle beteiligten Variablen und die Felder-Konfigurationen auf die gleiche Codierung eingestellt wurden.
Konfigurationsmöglichkeiten
Insgesamt gibt es 10 verschiedene Stellen, an denen eine Zeichencodierung konfiguriert oder angegeben werden kann. Das hört sich schlimmer an, als es am Ende ist. Einmalig während der Installation stellt man character-set-server
ein. Beim Anlegen von Datenbanken sollte CHARACTER SET angegeben werden, das sich durchvererbt bis zu den Feldern. Im täglichen Betrieb benötigt man dann nur noch ein Aushandeln der Codierung nach dem Verbindungsaufbau durch einen Client.
Der nachfolgend verwendete Ausdruck „erbt von“ bedeutet, dass bei Weglassen einer Angabe der Wert von einer anderen Stelle übernommen wird.
Konfigurationsoptionen
- character-set-server
- Das ist der Default-Konfigurationswert für den gesamten Server.
- character-set-filesystem
- Dateinamen in Statements wie
LOAD DATA INFILE
oderSELECT … INTO OUTFILE
werden gegebenenfalls nachcharacter-set-filesystem
übersetzt, bevor auf das Dateisystem zugegriffen wird.
Konfigurationsvariablen
- character_set_system
- In dieser Codierung werden Bezeichner (Datenbank-, Tabellen- und Feldnamen) gespeichert. Als Anwender hat man keinen Einfluss darauf, denn der Wert steht immer auf UTF-8.
- character_set_database
- Dieser Wert kann nicht selbst gesetzt werden. Er wird vom Server immer auf den Wert aus der Datenbank gesetzt, die man mit
USE …
wählt. Ist keine gewählt, entspricht ercharacter-set-server
. Verwendet wird er fürcharacter_set_connection
, wenn mitSET CHARACTER SET
(stattSET NAMES
) die Codierung der aktuellen Client-Verbindung eingestellt werden soll. - character_set_client, character_set_connection und character_set_results
- Diese drei Werte wurden bereits im vorhergehenden Abschnitt erläutert. Sie erben von
character-set-server
.
Weitere Stellen
- Datenbank
- Beim Anlegen von Datenbanken wird
character-set-server
als Defaultwert verwendet. Überschreiben kann man ihn mit:CREATE DATABASE … CHARACTER SET …
- Tabelle
- Wird von der Datenbank geerbt, wenn nicht mit
CREATE TABLE tabellenname (felder-definition) CHARACTER SET …
ein anderer Wert vergeben wird. Die Codierungsangabe der Tabelle hat keine weitere Aufgabe als den Default-Wert für neu anzulegende String-Felder zu stellen. - String-Felder
- Wird von der Tabelle geerbt, wenn nichts anderes angegeben wurde.
- Beispiel:
CREATE TABLE tabellenname (feldname VARCHAR(länge) CHARACTER SET …, weitere Felder)
– Bei allen Lese- und Schreibvorgängen wird der individuelle Feldwert berücksichtigt und die Daten gegebenenfalls von und in diese Codierung umkodiert. - String-Literal
- Jedem String-Literal (eine in Anführungszeichen eingeschlossene Zeichenfolge) kann ein Codierungsbezeichner vorangestellt werden. Das wird man üblicherweise nicht benötigen, weil es anstrebenswert ist, nur eine einzige Codierung für alles zu verwenden. SQL-Statements und die Strings darin werden ohne weitere Angabe gemäß
character_set_client
interpretiert. Beispiel:SELECT _utf8'string'