无法将表情符号存储在数据库中

Posted

技术标签:

【中文标题】无法将表情符号存储在数据库中【英文标题】:Cannot store emoji in database 【发布时间】:2017-01-12 13:27:25 【问题描述】:

情况

如果这个问题已经被问过,但解决方案对我不起作用,请提前道歉。

无论我尝试什么,我都无法将表情符号存储在我的数据库中。它们保存为????。 唯一正确保存的表情符号是只需要 3 个字节的表情符号,例如害羞的脸或太阳。

实际的 utf8mb4 不起作用。

它已经在 androidios 上进行了测试。结果相同。

版本

mysql:5.5.49 CodeIgniter:3.0.0

步骤

    我已修改数据库字符集和排序规则属性。

    ALTER DATABASE my_database CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci

    我已经修改了表格字符集和排序规则属性。

    ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci

    如果可能,我已将表格的每个字段设置为编码:UTF-8(ut8mb4) 和排序规则:utf8mb4_unicode_ci

    我在 CodeIgniter 应用中修改了数据库连接。

    我运行了以下命令:SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci

    最后我也试过这个: REPAIR TABLE table_name; OPTIMIZE TABLE table_name;

一切都应该正确设置,但它不起作用。

数据库设置

这是运行以下命令的结果:

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

表格设置

表格结构的截图:

数据库连接

这些是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');

和其他两个类似的????还有????

它们被毫无问题地插入到表中:

但在实际应用中,我真正看到的是:?(这次只有一个?而不是 4 个)

【问题讨论】:

看起来你可能已经读过这个,如果不是在这里:mathiasbynens.be/notes/mysql-utf8mb4。问:您从哪里运行SHOW VARIABLES ... 查询?命令行? PHPMyAdmin?例如,通过 PHPMyAdmin 运行命令可能会产生一些您不期望的值,因为您使用的是 phpmyadmin 连接,因此这些值取决于 phpmyadmin 的连接方式。 您好@johnnyfittizio 您在消息字段中使用什么排序规则? @GerardRoche 是的,我在 PHPMyAdmin 中运行它,所以我不应该担心这个结果吗?是的,我已按照该教程进行操作,但不幸的是无法正常工作。 看起来服务器配置不正确。我在本地检查,甚至从 PHPMyAdmin 我的配置都是正确的。仔细检查配置,因为您的配置显然不正确。它们应该与文章中的完全一样。调试:确保部分的顺序是[client][mysql][mysqld],就像文章中一样(这可能并不重要),确保 mysql 已重新启动(不仅仅是重新加载)。显示数据库结构,它是否具有正确的字符集和排序规则。通过 CLI 尝试 SHOW VARIABLES ... 查询。 是的,一定有什么问题。在 my.cnf 中,我将 character-set-server 设置为 utf8mb4,但是当我检查它时它是 latin1。所以有一些东西可以覆盖它。我会尝试联系服务器。顺便说一句,您知道如何通过 CLI 运行该查询 SHOW VARIABLES 吗? 【参考方案1】:

好吧,我终于成功了! 感谢所有试图帮助我的人,尤其是@Rick James 和@Gerard Roche。

建议:

如果您需要使用表情符号,首先在 localhost 上进行简单的测试。创建一个新数据库并制作一个新的应用程序用于测试目的。

如果您按照我在问题中写的步骤或按照本教程进行操作:https://mathiasbynens.be/notes/mysql-utf8mb4#utf8-to-utf8mb4 它必须有效。

在本地开发一个全新的基本应用程序,您将拥有更多控制权和更多空间来进行所需的所有测试。

解决方案:

就我而言,问题在于 CodeIgniter 中的数据库配置。它没有正确设置 char_set 和排序规则以进行愚蠢的忽略:我覆盖了保存消息的函数中的数据库设置,以确保它与移动数据库一起使用。

之前:

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       

之后:

function message_save ( $data = FALSE )

    $mobile_db_connection = $this->load->database('admin_mobile_mh', TRUE);

    // other code to save message

结论:

应用程序必须正确设置与数据库的连接。 如果您正确设置了数据库,但没有与您的应用建立正确的连接,它将无法正常工作。

因此,如果您遇到类似问题,请确保 api 正确设置 char_setutf8mb4db_collatutf8mb4_unicode_ci

【讨论】:

【参考方案2】:

我知道为 Emoji 获取 ???? 的唯一方法是不要将 声明为 utf8mb4。我了解到您显然已经确定该列是这样声明的,但请运行SHOW CREATE TABLE table_name; 进一步确认。

如果列覆盖CHARACTER SET,则系统默认值、数据库默认值和表默认值无关。

对所有其他尝试回答的注释:COLLATION 无关紧要,只有 CHARACTER SET 与此问题相关

【讨论】:

感谢您的回复。我已经编辑了问题,包括 SHOW CREATE TABLE 的结果。对吗? CREATE TABLE 看起来正确。接下来要检查:SELECT message, HEX(message) ... 查看十六进制的问号。我希望看到????3F3F3F3F,这意味着问题发生在插入期间。 什么是创建表情符号?可能是???? before 插入?有没有办法重新运行插入并在插入之前获得十六进制 谢谢我已经编辑了这个问题,添加了我在表格中插入一些表情符号的部分,这些表情符号已正确插入表格,但现在正确显示(取自表格)。但抱歉我不知道如何正确运行HEX。不工作。【参考方案3】:

首先加载my.cnf,然后加载conf.d/*.cnf

不要修改my.cnf *(可能会被conf.d/*.cnf 中的配置覆盖),而是创建一个自定义覆盖配置,例如conf.d/90-my.cnf.

前缀 90 确保自定义设置最后加载,这意味着它们会覆盖任何之前的设置。

为确保重新加载新配置,请参阅Reload Without Restarting the MySQL service。

示例配置结构 (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://***.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

【讨论】:

【参考方案4】:

您可以将 Table 字段值更改为 utf8mb4,而不是 varchar

除了设置客户端和服务器字符集(例如ALTER TABLE mytable charset=utf8mb4, MODIFY COLUMN textfield1 VARCHAR(255) CHARACTER SET utf8mb4,MODIFY COLUMN textfield2 VARCHAR(255) CHARACTER SET utf8mb4; 等等。

【讨论】:

感谢您的回答。我已经这样做了。为了确定,我又做了一次,但结果还是一样:( 是的。但是整理服务器(如图所示)是 latin1_swedish_ci。您认为问题可能与服务器有关吗? 把那个也改成utf8mb4_unicode_ci,我们试试看【参考方案5】:

您好,我在 android 中使用过 EMOJI,并使用 EMOJI_INDEX 将其存储到 orm 数据库。我以字符串形式保存在数据库中的普通消息中,但是当我得到那个时间时,我检查是否有任何表情符号然后将其转换为那里的过程表情符号。

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);
        
    

欲了解更多信息,请查看here。 谢谢希望这会对你有所帮助。

【讨论】:

【参考方案6】:

我在 linux 上的服务器版本有问题。我不得不手动更改文件 database_interface.lib.php 并围绕这个

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

改变它,变成这样:(注意 utf8mb4_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
        );
    

【讨论】:

【参考方案7】:

更新答案

您可以尝试使用字符集utf8 排序规则utf8_unicode_ci 而不是utf8mb4_unicode_ci

运行此查询

ALTER TABLE table_name CHANGE `column_name` `column_name` TEXT CHARSET utf8 COLLATE utf8_unicode_ci;

旧答案 您应该使用排序规则 utf8mb4_bin 而不是 utf8mb4_unicode_ci

运行此查询

 ALTER TABLE table_name CHANGE `column_name` `column_name` TEXT CHARSET utf8mb4 COLLATE utf8mb4_bin;

表情符号将作为代码存储并在 Android 和 iOS 应用程序中再次转换为表情符号。我也在我的项目中使用过这段代码。

【讨论】:

感谢您的回复。我曾尝试将排序规则 utf8mb4_bin 用于消息字段,但不幸的是它们仍保存为 ???? 排序规则用于字符set中的字符comparison。你的答案是错误的,我不赞成它,因为它是错误的。排序与这个问题的关系实际上与我 2 分钟前洒出的一杯水一样多。

以上是关于无法将表情符号存储在数据库中的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能在这个 mysql 字段中存储 4 字节的表情符号?

允许 MySQL 以 utf8mb4 编码存储表情符号?

从 iPhone 到 Python/Django 的表情符号

表情符号未正确存储在 MySQL 5.6 中,排序规则为 utf8mb4

Discord bot 动画表情符号无法获取并用作反应

如何使用 javascript 检测表情符号