UTF8 MySQL在Rails上的问题 - utf8_general_ci编码问题

21

我有一个暂存的Rails网站,它正在运行MySQL 5.0.32-Debian。

在这个特定的网站上,我的所有表都使用utf8/utf8_general_ci编码。

在该数据库中,我有一些数据看起来像这样:

mysql> select * from currency_types limit 1,10;
+------+-----------------+---------+
| code | name            | symbol  |
+------+-----------------+---------+
| CAD  | Canadian Dollar | $       |
| CNY  | Chinese Yuan    | å…ƒ     |
| EUR  | Euro            | €     |
| GBP  | Pound           | £      |
| INR  | Indian Rupees   | ₨     |
| JPY  | Yen             | ¥      |
| MXN  | Mexican Peso    | $       |
| USD  | US Dollar       | $       |
| PHP  | Philippine Peso | ₱     |
| DKK  | Denmark Kroner  | kr      |
+------+-----------------+---------+

我遇到的问题如下:

在staging环境中(使用debian服务器运行数据库和Rails站点),当从Rails中显示时,符号的字符显示正确。例如,我在浏览器中看到中国元符号显示为元,而不是å…ƒ,这是它在数据库中显示的。

但是,当我将数据下载到我的本地OS X开发机器并在本地运行数据库和Rails时,我在浏览器中看到来自数据库内部的编码(å…ƒ),而不是像在staging中看到的字符元(元)。

我所做的调试

我确保每个web服务器(本地和staging)的Content-Type标头都返回为utf8。

我的本地mysql服务器和staging服务器都设置为使用utf8作为默认字符集。我在进行任何调用之前使用“set names 'utf8'”。

我甚至可以从我的OS X Rails主机连接到我的staging数据库,但我仍然看到表示元的字符å…ƒ。那么,也许我的mysql本地客户端存在问题,但我找不到问题所在。

也许这可能提供一些线索

更加混乱的是,如果我将字符元粘贴到我的本地机器上的数据库中,我可以在网页浏览器中正确显示它。但是,如果我将相同的字符粘贴到我的staging数据库中,我在页面上看到一个问号代替它。

另外,如果我在查询之前在我的OS X Rails机器上使用“set names 'latin1'”,则所有字符都可以正确返回。我以前将这些表设置为latin1 - 这可能是问题所在吗?

请有人帮帮我,我试图找出问题所在!

7个回答

29

哦!原来之前我将一些表格信息编码成了latin1,之后又愚蠢地将数据库转换为utf8而没有先进行转换。

运行以下代码修复了currency_types表格:

mysqldump -u root -p --opt --default-character-set=latin1 --skip-set-charset  DBNAME > DBNAME.sql

mysql -u root -p --default-character-set=utf8  DBNAME < DBNAME.sql

现在我只需要确保在从Latin1转换为UTF8之后生成的其他内容不会受到影响 :(


1
是的,这就是问题所在。但当您将连接设置为latin1时,它看起来正常,因为它进行了相同的转换。我曾经遇到过这个问题,但无法重新创建数据库。所以我将phpMyAdmin更改为使用latin1连接,然后导出(因此导出数据现在是正确的),然后删除该黑客并重新导入。数据已修复。详情请参见:http://omegadelta.net/2010/11/23/when-you-thought-the-db-was-utf-8-but-it-wasnt/ - William Denniss
谢谢!今天早上我一直在苦思冥想,结果这就是一个在我之前创建的数据库的解决方案! - Cymen
只有收到“拒绝访问”消息的Windows用户,应将 DBNAME.sql 更改为 %homepath%\DBNAME.sql,适用于mysqldump和mysql调用。感谢Subimage! - Alex B.
纯天才。干得好@Subimage。你的诊断是数据库转换为utf8而没有将数据转换为单个表中的数据,这正是我们情况发生的事情。你的解决方案也非常有效。 - Sujoy Gupta
在发现这个问题之前,我阅读了很多关于utf8-rails3-mysql的其他问题,结果发现这个票证实了我正在处理的网站上出现的问题。 - Jesse Clark
为我解决了问题,谢谢。 - NM Pennypacker

22

你的database.yml文件中的正确部分是否有这两行代码?

encoding: utf8
collation: utf8_general_ci

不知道yml文件可以有一个collation行,但是我确实有encoding的那个... - Subimage
1
为什么推荐使用 utf8_unicode_ci 而不是 utf8_general_ci? - mauriciomdea
@mauriciomdea 不错的问题:实际上,utf8_general_ci略快但不够准确。最佳做法是使用utf8_unicode_ci。在这里阅读更多信息:https://dev59.com/bnRA5IYBdhLWcg3w9izq - Joshua Pinter

2
  1. 问题可能出在你的MySQL客户端上,在staging环境下它可能不支持UTF-8。
  2. 你本地的OSX ruby安装配置可能没有声明正确的配置。你应该在MySQL数据库的"config/database.yml"中添加"encoding: utf8"。你应该在ruby环境的"config/environment.rb"中添加"$KCODE = 'u'"。

我没有$KCODE部分,但是在所有的配置文件中都有“encoding: utf8”。看起来我的问题是数据库中存在混合编码的内容。因此,我存储了Latin-1字符,但尝试将它们作为utf8读取。 - Subimage
我在发布这个消息后看到了你的回答。无论如何,感谢你指出这个错误。我已经看到许多情况下出现了这个错误。 - yrcjaya

1
另一个简单的方法是使用SQL Alter语句设置编码类型。您可以使用以下bash脚本来完成此操作。
for t in $(mysql --user=root --password=admin  --database=DBNAME -e "show tables";);do echo "Altering" $t;mysql --user=root --password=admin --database=DBNAME -e "ALTER TABLE $t CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;";done

美化

  for t in $(mysql --user=root --password=admin  --database=DBNAME -e "show tables";);
    do 
       echo "Altering" $t;
       mysql --user=root --password=admin --database=DBNAME -e "ALTER TABLE $t CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;";
    done

0

对于Rails,请在rails控制台中运行以下代码片段。它将为所有表生成一个SQL语句。然后登录到mysql并执行从rails控制台复制的SQL语句。它将更改所有表的编码。

schema = File.open('db/schema.rb', 'r').read
rows = schema.split("\n")

table_name = nil
rows.each do |row|
  if row =~ /create_table/
     table_name = row.match(/create_table "(.+)"/)[1]
     puts "ALTER TABLE `#{table_name}` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"
  end
end

这不是 Rails 的方式,请尝试使用迁移。 - mauriciomdea

0

你可以按照 Rails 的方式生成迁移,以更改数据库的排序类型:

rails generate migration ChangeDatabaseCollation

然后您可以编辑生成的文件并粘贴:

def change
  # for each table that will store the new collation execute:
  execute "ALTER TABLE my_table CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci"
end

然后运行迁移:

rake db:migrate

你也可以在 database.yml 文件中强制使用新的排序规则:

development:
  adapter: mysql2
  encoding: utf8
  collation: utf8_general_ci

有关Rails迁移的更多信息:

http://edgeguides.rubyonrails.org/active_record_migrations.html

关于排序类型的更多信息:

http://collation-charts.org/


0

我的数据库默认已经设置为utf8,但我遇到了同样的问题。

此外,在添加了以下常见的meta标签后,问题仍然存在:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

然后我创建了一个专门的connection.php文件,以确保与MySQL的所有通信都设置为字符集utf8。请注意,在mysqli_set_charset($bd, 'utf8')中,utf8中没有-

这是我的Connection.php文件:

<?php
    $mysql_hostname = "localhost";
    $mysql_user = "username";
    $mysql_password = "password";
    $mysql_database = "dbname";
    $prefix = "";
    $bd = mysqli_connect($mysql_hostname, $mysql_user, $mysql_password) or die("Could not connect database");
    mysqli_select_db($bd, $mysql_database) or die("Could not select database");
    if(!mysqli_set_charset($bd, 'utf8'))  {
        exit() ;
    }
?>

另一个 PHP 文件:

<?php
    //Include database connection details
    require_once('connection.php');

    //Enter code here...

    //Create query
    $qry = "SELECT * FROM subject";
    $result = mysqli_query($bd, $qry);
?>

//Other stuff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接