web-dev-qa-db-ja.com

絵文字をデータベースに保存できません

状況

この質問がすでに行われている場合は、事前に申し訳ありませんが、解決策が私のために機能していません。

何をしようとしても、データベースに絵文字を保存できません。それらは_????_として保存されます。
正しく保存される唯一の絵文字は、恥ずかしがり屋の顔や太陽のように、3バイトしか必要としないものです。

実際のutf8mb4は機能していません。

Database screenshot

Android=とIosの両方でテストされています。同じ結果が得られます。

[〜#〜]バージョン[〜#〜]

Mysql:5.5.49
CodeIgniter:3.0.0

手順

  1. データベースの文字セットと照合プロパティを変更しました。

    _ALTER DATABASE my_database CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci_

  2. テーブルの文字セットと照合プロパティを変更しました。

    _ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci_

  3. 可能な場合、テーブルの各フィールドをEncoding:UTF-8(ut8mb4)およびCollat​​ion:_utf8mb4_unicode_ci_として設定しました

  4. CodeIgniterアプリでデータベース接続を変更しました。

  5. 私は以下を実行しました:_SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci_

  6. 最後に私もこれを試しました:_REPAIR TABLE table_name; OPTIMIZE TABLE table_name;_

すべてが適切に設定されているはずですが、それでも機能しません。

データベース設定

これは、次のコマンドを実行した結果です。

_`SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';`
_

Database settings

テーブル設定

テーブル構造のスクリーンショット:

Table settings

データベース接続

これらは、database.php内のデータベース接続設定です(これが唯一のデータベースではないことに注意してください。utf8を使用して接続する他のデータベースもあります)

_$db['my_database'] = array(
        'dsn'           => '',
        'hostname'      => PROJECT_DATABASE_HOSTNAME,
        'username'      => PROJECT_DATABASE_USERNAME,
        'password'      => PROJECT_DATABASE_PASSWORD,
        'database'      => PROJECT_DATABASE_NAME,
        'dbdriver'      => 'mysqli',
        'dbprefix'      => '',
        'pconnect'      => FALSE,
        'db_debug'      => TRUE,
        'cache_on'      => FALSE,
        'cachedir'      => '',
        'char_set'      => 'utf8mb4',
        'dbcollat'      => 'utf8mb4_unicode_ci',
        'swap_pre'      => '',
        'encrypt'       => FALSE,
        'compress'      => FALSE,
        'stricton'      => FALSE,
        'failover'      => array(),
        'save_queries'  => TRUE
    );
_

MY.CNF設定

これは、my.cnfファイルの内容全体です。

_[mysqld]
default-storage-engine=MyISAM
innodb_file_per_table=1
max_allowed_packet=268435456
open_files_limit=10000
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4
_

質問

なぜうまくいかないのか知っていますか?何か不足していますか?

仮説1

よくわかりませんが、問題の原因は次のとおりです。

My.cnfで確認できるように、_character-set-server_は_utf8mb4_として明確に設定されています。

しかし、データベースでクエリを実行した後:

_SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';_

結果はその_character-set-server = latin1_

なぜだか分かりますか?実際に更新されないのはなぜですか?

仮説2

アプリケーションはいくつかの異なるデータベースを使用します。これはutf8mb4に設定されていますが、他のすべてはutf8に設定されています。別々のデータベースでも問題になるのでは?

ありがとうございました!

編集:

これは_SHOW CREATE TABLE app_messages;_の結果です

_CREATE TABLE `app_messages` (
  `message_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `project_id` bigint(20) NOT NULL,
  `sender_id` bigint(20) NOT NULL,
  `receiver_id` bigint(20) NOT NULL,
  `message` text COLLATE utf8mb4_unicode_ci,
  `timestamp` bigint(20) DEFAULT NULL,
  `is_read` enum('x','') COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`message_id`)
) ENGINE=InnoDB AUTO_INCREMENT=496 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
_

編集2:

次のコマンドを実行しました。

_INSERT INTO app_messages (message_id, project_id, sender_id, receiver_id, message, timestamp, is_read)
VALUES ('496','322','77','188', '????' ,'1473413606','x');
_

そして、他の2つは????そして????

それらは問題なくテーブルに挿入されました:

enter image description here

しかし、実際のアプリで私が実際に目にするのは、_?_(今回は1つだけですか?4ではありません)です。

19
FrancescoMussi

さて、ようやくそれを機能させることができました!私を助けてくれたすべての人、特に@Rick Jamesと@Gerard Rocheに感謝します。

提案:

絵文字を扱う必要がある場合は、まずlocalhostで簡単なテストを行ってください。新しいデータベースを作成し、テスト用の新しいアプリを作成します。

私が質問に書いた手順に従う場合、またはこのチュートリアルに従う場合: https://mathiasbynens.be/notes/mysql-utf8mb4#utf8-to-utf8mb4 動作するはずです。

新しい基本的なアプリでローカルに作業すると、必要なすべてのテストを実行するためのより多くの制御と余地が得られます。

解決策:

私の場合、問題はCodeIgniterのデータベースの構成にありました。 char_setと愚かな見落としの照合順序を適切に設定していませんでした。モバイルデータベースで確実に機能するように、メッセージを保存する関数のデータベース設定を上書きしていました。

BEFORE:

function message_save ( $data = FALSE )
{   
    $project_db_config                  = array();
    $project_db_config['hostname']      = 'MY_Host';
    $project_db_config['username']      = 'MY_USERNAME';
    $project_db_config['password']      = 'MY_PASSWORD';
    $project_db_config['database']      = 'MY_DATABASE';

    $mobile_db                          = $this->load->database( $project_db_config, TRUE );

    // other code to save message       
}

AFTER:

function message_save ( $data = FALSE )
{
    $mobile_db_connection = $this->load->database('admin_mobile_mh', TRUE);

    // other code to save message
}

結論:

アプリはデータベースへの接続を適切に設定する必要があります。データベースが適切に設定されているが、アプリと適切に接続していない場合、データベースは機能しません。

したがって、同様の問題が発生した場合は、APIがchar_set なので utf8mb4およびdb_collat なので utf8mb4_unicode_ci

3
FrancescoMussi

絵文字の????を取得するために知っている唯一の方法は、columnを宣言しないことですutf8mb4。列がそのように宣言されているようですが、SHOW CREATE TABLE table_name;を実行してさらに確認してください。

列がCHARACTER SETをオーバーライドする場合、システムのデフォルト、データベースのデフォルト、およびテーブルのデフォルトは無関係です。

他のすべての試行された回答へのメモ:COLLATIONは無関係であり、CHARACTER SETのみが関連しますこの質問の場合

1
Rick James

my.cnfが最初にロードされ、次にconf.d/*.cnfがロードされます。

my.cnf *(conf.d/*.cnfの設定によってオーバーライドされる可能性があります)を変更する代わりに、カスタムオーバーライド設定を作成します。 conf.d/90-my.cnf

接頭辞90は、カスタム設定が最後に読み込まれることを保証します。つまり、以前に設定された設定を上書きします。

新しい設定が確実にリロードされるようにするには、 MySQLサービスを再起動せずにリロードする をご覧ください。

構成構造の例(Linux)

.
├── conf.d
│   ├── 90-my.cnf
│   ├── conn.cnf
│   ├── my5.6.cnf
│   └── mysqld_safe_syslog.cnf
├── debian.cnf
├── debian-start
└── my.cnf

conf.d/90-my.cnf

# https://mathiasbynens.be/notes/mysql-utf8mb4
# http://stackoverflow.com/q/3513773/934739

[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

[mysqld]

character-set-client-handshake = FALSE

# The server character set and collation are used as default values if the
# database character set and collation are not specified in CREATE DATABASE
# statements. They have no other purpose.
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
1
Gerard Roche

こんにちは[〜#〜] emoji [〜#〜]Androidで使用し、ormデータベースを使用してEMOJI_INDEX。私は通常のメッセージを文字列形式でdbに保存しましたが、その時間になったらチェックします絵文字がある場合は、その絵文字に変換します。

textMessage.setText(getItem(pos).file != null ? "":EmojiUtil.getInstance(context).processEmoji(getItem(pos).message, textMessage.getTextSize()));

ここからEmoji_Indexを処理に変更する方法を見てください

if (emojiImages == null || emojiImages.isRecycled()) {
        InputStream localInputStream;
        try {
            localInputStream = context.getAssets().open("emoji/emoji_2x.png");
            Options opts = new Options();
            opts.inPurgeable = true;
            opts.inInputShareable = true;
            emojiImages = BitmapFactory.decodeStream(localInputStream, null, opts);
        } catch (IOException e) {
            return Html.fromHtml(paramString);
        }
    }

詳細については、 ここ を参照してください。これがあなたに役立つことを願ってありがとう。

0
Saveen

Varcharの代わりに、次のようにテーブルフィールド値を_utf8mb4_に変更できます。

クライアントとサーバーの文字セットの設定に加えて、すべてのテーブルのデフォルトの文字セットとテキストフィールドがutf8mb4に変換されていることを確認してください。 ALTER TABLE mytable charset=utf8mb4, MODIFY COLUMN textfield1 VARCHAR(255) CHARACTER SET utf8mb4,MODIFY COLUMN textfield2 VARCHAR(255) CHARACTER SET utf8mb4;など。

0
Naresh Kumar P

Linuxのサーバーバージョンに問題がありました。私は手動でこの周りにファイルdatabase_interface.lib.phpを変更する必要がありました

if(!PMA_DRIZZLE){if(!empty($ GLOBALS ['collat​​ion_connection'])){

これが次のようになるように変更します:(tf8mb4_unicode_ciの参照に注意してください)

    // Skip charsets for Drizzle
if (!PMA_DRIZZLE) {
    if (! empty($GLOBALS['collation_connection'])) {
        PMA_DBI_query("SET CHARACTER SET 'utf8mb4';", $link, PMA_DBI_QUERY_STORE);
        $set_collation_con_query = "SET collation_connection = '"
            . PMA_Util::sqlAddSlashes($GLOBALS['collation_connection']) . "';";
        PMA_DBI_query(
            $set_collation_con_query,
            $link,
            PMA_DBI_QUERY_STORE
        );
    } else {
        PMA_DBI_query(
            "SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci';",
            $link,
            PMA_DBI_QUERY_STORE
        );
    }
}
0
Miguel