できない.dev

MySQL で「Incorrect string value」が出て絵文字を保存できない

絵文字は 4 バイト必要で、utf8mb3 では格納できないために出るエラー。
テーブル・カラム・接続のすべてを utf8mb4 に揃えれば解決する。
どれか一つでも取り残すと再発する。

公開:

要約

Incorrect string value: '\xF0\x9F...' for column ... は、4 バイトの文字を 4 バイト格納できない文字コードのカラムへ入れようとしたときに出る。

絵文字や一部の漢字は UTF-8 で 4 バイトを要する。
MySQL の utf8mb4 は 4 バイトを扱えるが、utf8mb3 は 3 バイトまでで、そもそも格納できない。
テーブル・カラム・接続を utf8mb4 に揃えるのが解決策である。

よくある原因

  1. カラムが utf8mb3: 古い定義のまま作られたテーブルへ絵文字を入れようとしている。
  2. 接続が utf8mb4 でない: 保存先が正しくても、接続の文字コードが違えば送信時点で壊れる。
  3. データベース既定が古い: 新しく作るテーブルが自動的に utf8mb3 になる。
  4. 別名 utf8 の指定: utf8 は utf8mb3 の非推奨な別名で、指定しても 4 バイトは扱えない。

解決策

1. 現状の文字コードを確認する

SHOW CREATE TABLE posts;
SHOW VARIABLES LIKE 'character_set%';

テーブル定義と接続の両方を見る。
片方だけ直しても再発する。

2. テーブルを utf8mb4 に変換する

ALTER TABLE posts CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;

CONVERT TO CHARACTER SET はテーブル内の文字列カラムをまとめて変換する。
MySQL 8.0 の既定の照合順序は utf8mb4_0900_ai_ci である(公式ドキュメント(新しいタブで開く))。

3. データベース既定を変える

ALTER DATABASE app_db CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;

以降に作るテーブルが utf8mb4 になる。
既存テーブルは変わらないので、個別に変換する。

4. 接続の文字コードを合わせる

SET NAMES utf8mb4;

アプリからは接続文字列やドライバの設定で指定するのが確実である。
Node.js の mysql2 なら charset: "utf8mb4"、Python の PyMySQL なら charset="utf8mb4" を渡す。

5. 桁あふれに注意する

utf8mb4 は 1 文字あたり最大 4 バイトを使うため、インデックスの長さ制限に当たることがある。
その場合は対象カラムの長さを見直す。

この記事は役立ちましたか?