Wer in seiner Applikation auf UTF-8 als Zeichensatz setzt, wird in den entsprechenden Spalten einer MySQL-Tabelle in der Regel auch auf Kollationen wie utf8_unicode_ci oder das ältere utf8_general_ci setzen. Dass dies allerdings zu Problemen mit Umlauten führen kann, zeige ich euch im folgenden Beitrag.

Konfiguration

Als Ausgangsgrundlage sei angenommen, dass ihr euren MySQL-Server korrekt konfiguriert habt. Hierfür könnt ihr die Anleitung von Gerd Riesselmann zu Rate ziehen.

Beispiel

Für unser Beispiel greifen wir auf die Tabelle aus der verlinkten Anleitung, passen sie jedoch an einer kleinen Stelle an: Wir möchten, dass die Tabelle nur einzigartige Werte enthält:

create table sorttest (value varchar(15) unique) default character set 'UTF8';

Mit folgendem Befehl könnt ihr überprüfen, dass für die Spalte value die Kollation utf8_unicode_ci benutzt wird.

mysql> SHOW FULL COLUMNS FROM sorttest;
+-------+-------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
| Field | Type        | Collation       | Null | Key | Default | Extra | Privileges                      | Comment |
+-------+-------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
| value | varchar(15) | utf8_unicode_ci | YES  | UNI | NULL    |       | select,insert,update,references |         |
+-------+-------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
1 row in set (0.00 sec)

Nun versuchen wir die Zeichenketten 'aaa' und 'äää' einzufügen.

mysql> INSERT INTO sorttest values('aaa');
Query OK, 1 row affected (0.03 sec)

mysql> INSERT INTO sorttest values('äää');
ERROR 1062 (23000): Duplicate entry 'äää' for key 'value'

Oha, das funktioniert also nicht. 'aaa' und 'äää' sollen identisch sein.

Erklärung

In der offiziellen Dokumentation von MySQL findet sich in der Beschreibung der Unicode-Zeichensätze folgendes Zitat:

Die folgenden Gleichstellungen beispielsweise sind sowohl in utf8_general_ci als auch in utf8_unicode_ci zutreffend:

Ä = A
Ö = O
Ü = U

Wenn man sich mal umschaut wird man feststellen, dass recht viele Projekte diese Kollationen verwenden, wo es auch zu konkreten Problemen führt. Ein konkretes Beispiel ist eine Benutzertabelle in denen Benutzernamen gespeichert werden. Existiert bspw ein Benutzer "foobär", wird es beim Versuch den Benutzer "foobar" zu speichern, zu einem Fehler kommen. foobar ist nun mal identisch mit foobär. Zumindest in utf8_general_ci als auch in utf8_unicode_ci.

utf8_bin

Die Lösung für unser Problem lautet die Kollation utf8_bin. Hier werden die einzelnen Buchstaben auf Binärebene überprüft. Hier muss allerdings beachtet werden, dass bei utf8_bin Groß- und Kleinbeschreibung eine Rolle spielt, im Gegensatz zu utf8_general_ci und in utf8_unicode_ci (Case insensitive).

Passen wir nun unser Beispiel von oben an, können wir beide Einträge speichern:

mysql> create table sorttest2 (value varchar(15) unique) default character set 'UTF8' collate utf8_bin;
mysql> show full columns from sorttest2;
+-------+-------------+-----------+------+-----+---------+-------+---------------------------------+---------+
| Field | Type        | Collation | Null | Key | Default | Extra | Privileges                      | Comment |
+-------+-------------+-----------+------+-----+---------+-------+---------------------------------+---------+
| value | varchar(15) | utf8_bin  | YES  | UNI | NULL    |       | select,insert,update,references |         |
+-------+-------------+-----------+------+-----+---------+-------+---------------------------------+---------+
1 row in set (0.00 sec)

mysql> insert into sorttest2 values('aaa');
Query OK, 1 row affected (0.00 sec)

mysql> insert into sorttest2 values('äää');
Query OK, 1 row affected (0.00 sec)

mysql> select value from sorttest2;
+--------+
| value  |
+--------+
| aaa    |
| äää    |
+--------+
2 rows in set (0.00 sec)
blogroll
tags