【问题标题】:UTF-8 Character in Java becomes Invalid Character in MySQLJava 中的 UTF-8 字符在 MySQL 中变为无效字符
【发布时间】:2018-07-28 00:09:00
【问题描述】:

具有来自基于外部 REST / JSON 的数据源的值作为特殊字符。我使用预先存在的实用程序 CharDecoder.java 对其进行转换,它保持不变,但在将其插入 MySQL 数据库(默认字符集为 UTF-8)后,它会从 ć 变为 ?。

我的程序流程是这样的:

外部数据源发送 JSON --> CharDecoder(在 tomcat7 的 war 文件中,处理特殊字符)然后填充一行 --> 在 MySQL 数据库中。

MySQL 数据库中的最终结果是无效字符。

开发环境信息:

  1. 我正在使用 Java 1.7。

  2. Maven 3.3.3,在我的 pom.xml 的 <properties> 标签内:

    UTF-8

  3. MacOS 上的 Eclipse Oxygen。

我在 macOS 上运行 Eclipse Oxygen - 在项目的属性视图中(单击项目并 ⌘I 也称为 COMMAND+I),它指出文本文件编码为 UTF-8。

当我使用代码库中的实用程序类对其进行转换时,它可以工作,但是当更新 MySQL 数据库中的行(该表的默认字符集是 UTF-8)时,它变成了无效字符。

所以,我将这个字符添加到我的 chars 数组中:“ć”(它位于以“î”开头的同一行)。

public class CharDecoder {
    
    public final static String chars [] = 
    {
        "ö", "ä", "ü", "Ö", "Ä", "Ü", "ß",
        "?", "\\", ",", ":", ";", "#", "+", "~", "!", "\"", "§", "$", "%",
        "&", "(", ")", "=", "<", ">", "{", "[", "]", "}", "/", "â", "ê",
        "î", "ô", "û", "Â", "Ê", "Î", "Ô", "Û", "á","ć", "é", "í", "ó", "ú",
        "Á", "É", "Í", "Ó", "Ú", "à", "è", "ì", "ò", "ó", "ù", "Á", "É", "Í",
        "Ó", "Ú", "°", "³", "²", "€", "|", "^", "`", "´", "'", " ", "@",
        "~", "*"
    };

    public final static String charsHtml[] = 
    { 
        "ö", "ä", "ü", "Ö", "Ä", "Ü",
        "ß", "?", "\\", ",", ":", ";", "#", "+", "&tilde;", "!", "\"",
        "&sect;", "$", "%", "&amp;", "(", ")", "=", "&lt;", "&gt;", "{",
        "[", "]", "}", "/", "&acirc;", "&ecirc;", "&icirc;", "&ocirc;",
        "&ucirc;", "&Acirc;", "&Ecirc;", "&Icirc;", "&Ocirc;", "&Ucirc;",
        "&aacute;", "&eacute;", "&iacute;", "&oacute;", "&uacute;",
        "&Aacute;", "&Eacute;", "&Iacute;", "&Oacute;", "&Uacute;",
        "&agrave;", "&egrave;", "&igrave;", "&ograve;", "&Ugrave;",
        "&Agrave;", "&Egrave;", "&Igrave;", "&Ograve;", "&Ugrave;",
        "&deg;", "&sup3;", "&sup2;", "&euro;", "|", "&circ;", "`",
        "&acute;", "'", " ", "@", "~", "*"
    };
    
    public final static String entities[] = { 
        "F6", "E4", "FC", "D6", "C4",
        "DC", "DF", "3F", "5C", "2C", "3A", "3B", "23", "2B", "7E", "21",
        "22", "A7", "24", "25", "26", "28", "29", "3D", "3C", "3E", "7B",
        "5B", "5D", "7D", "2F", "E2", "EA", "EE", "F4", "FB", "C2", "CA",
        "CE", "D4", "DB", "E1", "E9", "ED", "F3", "FA", "C1", "C9", "CD",
        "D3", "DA", "E0", "E8", "EC", "F2", "F9", "C1", "C9", "CD", "D3",
        "DA", "B0", "B3", "B2", "80", "7C", "5E", "60", "B4", "27", "20",
        "40", "98", "2A"
    };

    public static String inputToChar(String input) {
        return (inputTo(input, chars));
    }

    public static String inputTo(String input, String[] tc) {
        StringBuilder sb = new StringBuilder();
        boolean entity = false;
        input = input.replace ('+', ' ');
        String tokens = tc == charsHtml ? "%<>" : "%";
        for (StringTokenizer st = new StringTokenizer (input, tokens, true); st.hasMoreTokens(); ) {
        String token = st.nextToken();
        if (entity) {
            boolean replaced = false;
            for (int i = 0; i < entities.length; i++) {
                if (token.startsWith (entities[i])) {
                    sb.append (tc[i]);
                    sb.append (token.substring (2));
                    replaced = true;
                    break;
                }
            }
            if (!replaced) {
                sb.append (token);
            }
            entity = false;
         } 
         else if (token.equals ("%")) {
            entity = true;
            continue;
         } 
         else if (token.equals ("<")) {
            sb.append ("&lt;");
         } 
         else if (token.equals (">")) {
            sb.append ("&gt;");
         } 
         else {
            sb.append (token);
         }
      }
      return (sb.toString ());
   }

   public static void main(String [] args) {
        String person1 = CharDecoder.inputToChar("Lukić");
        System.out.println(person1);
   }
}

为了让这个问题更直接,我删除了刚刚创建的 main() 方法的 JDBC 代码(一个简单的 JDBC 更新查询)。当我运行这个 main() 方法时,输出是:

Lukić

这很好,也是我想要的。但是,当我使用 Spring JDBC 更新它时,在 MySQL 数据库中(哪个表的默认字符集是 UTF-8)它变成:

Luki?

这肯定发生在数据库端,我应该更改它(表的默认字符集为 LATIN1)吗?

我是否必须将整个数据库的默认字符集更改为 LATIN1?我只是把想法扔在那里......

有没有办法在不更改默认字符集的情况下解决这个问题(不想破坏任何现有数据)...

【问题讨论】:

  • 你的方法entityTo在哪里?并且您在主定义上有一个错字public static main void 应该是public static void main
  • 我使用CharDecoder.inputToChar("Lukić"); 测试了您的代码,它在这里运行良好。我怀疑您的项目设置未配置为 UTF-8(如果您在 Eclipse 中选择类或项目并按 CTRL+ENTER)
  • @JorgeCampos - 谢谢,它是 inputToChar("("Lukić")。它在 maven 中设置为 UTF-8。抱歉,我在 macOS 上使用 Eclipse,所以 CNTRL+ENTER) 没有为我做任何事情。我现在将编辑和添加 maven。
  • 好吧,这可能是你的设置环境的问题,看看这个帖子:stackoverflow.com/questions/4606570/os-x-terminal-utf-8-issues 顺便问一下,你对这些转换的最终目标是什么?它有规范化类。看这里:docs.oracle.com/javase/tutorial/i18n/text/normalizerapi.html
  • @JorgeCampos 这不是 macOS 问题,而是 MySQL 问题,因为 MySQL 在 MacOS 和 Linux 上运行,而在 Linux 中也会发生同样的事情。

标签: java mysql spring-jdbc


【解决方案1】:

使用Unicode=yes&characterEncoding=UTF-8

把它放到你的数据库 url

【讨论】:

  • ?zeroDateTimeBehavior=convertToNull&amp;useUnicode=true&amp;characterEncoding=UTF-8 - 感谢您的建议帮助我找到了解决方案。
【解决方案2】:

如果你想拥有 FULL Unicode 支持,你不妨一路走下去:

character_set_server=utf8mb4

见:What is the difference between utf8mb4 and utf8 charsets in mysql?

【讨论】:

    猜你喜欢
    • 2012-05-02
    • 2013-12-22
    • 2010-11-28
    • 1970-01-01
    • 2023-03-23
    • 2014-02-26
    • 2018-09-14
    • 2020-03-07
    • 1970-01-01
    相关资源
    最近更新 更多