【问题标题】:UTF-8 won't persist on Hibernate + MySQLUTF-8 不会在 Hibernate + MySQL 上持续存在
【发布时间】:2015-06-02 14:51:15
【问题描述】:

我正在尝试使用 Hibernate 在 MySQL 数据库中保存一些值,但大多数立陶宛字符不会被保存,包括 ąĄ čČ ęĘ ėĖ įĮ ųŲ ūŪ(它们被保存为 ?),但是,šŠ žŽ 会被保存.

如果我手动插入,那么这些值会正确保存,因此问题很可能出在 Hibernate 配置中。

到目前为止我所尝试的:

hibernate.charset=UTF-8
hibernate.character_encoding=UTF-8
hibernate.use_unicode=true

---------

properties.put(PROPERTY_NAME_HIBERNATE_USE_UNICODE,
            env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_USE_UNICODE));
    properties.put(PROPERTY_NAME_HIBERNATE_CHARSET,
            env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_CHARSET));
    properties
            .put(PROPERTY_NAME_HIBERNATE_CHARACTER_ENCODING,
                    env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_CHARACTER_ENCODING));

---------

private void registerCharachterEncodingFilter(ServletContext aContext) {
    CharacterEncodingFilter cef = new CharacterEncodingFilter();
    cef.setForceEncoding(true);
    cef.setEncoding("UTF-8");
    aContext.addFilter("charachterEncodingFilter", cef)
            .addMappingForUrlPatterns(null, true, "/*");
}

here所述

我尝试将?useUnicode=true&characterEncoding=utf-8 添加到数据库连接网址。

如上所述here

我确保我的数据库设置为 UTF-8 字符集。 phpmyadmin > information_schema > schemata

def db_name utf8 utf8_lithuanian_ci NULL

这是我保存到数据库中的方式:

//Controller
buildingService.addBuildings(schema.getBuildings());
        List<Building> buildings = buildingService.getBuildings();
        System.out.println("-----------");
        for (Building b : schema.getBuildings()) {
            System.out.println(b.toString());
        }
        System.out.println("-----------");
        for (Building b : buildings) {
            System.out.println(b.toString());
        }
        System.out.println("-----------");

//Service:
@Override
public void addBuildings(List<Building> buildings) {
    for (Building b : buildings) {
        getCurrentSession().saveOrUpdate(b);
    }
}

第一组 println 包含所有立陶宛字符,第二组用 ? 替换大部分字符

编辑:添加详细信息

insert into buildings values (11,'ąĄčČęĘ', 'asda');    
select short, hex(short) from buildings;
//Šalt. was inserted via hibernate
//letters are properly displayed:
ąĄčČęĘ       | C485C484C48DC48CC499C498
MIF Šalt.    | 4D494620C5A0616C742E  

select address, hex(address) from buildings;
 Šaltini? <...> | C5A0616C74696E693F20672E2031412C2056696C6E697573
//should contain "ų"
--------
show create table buildings;
buildings | CREATE TABLE `buildings` (
  `id` int(11) NOT NULL,
  `short` varchar(255) COLLATE utf8_lithuanian_ci DEFAULT NULL,
  `address` varchar(255) COLLATE utf8_lithuanian_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_lithuanian_ci 

编辑: 我没有找到合适的解决方案,所以我想出了一个解决方法。我最终转义/取消转义字符,像这样存储它们:\uXXXX

【问题讨论】:

  • 这似乎不是您的具体问题,但我们遇到了类似的问题,Ant 构建脚本正在运行 sql 任务并且默认为主机的编码方案,即 cp1252在 windows server 2008 上。尽管我们的其余配置在整个过程中都指定了 UTF-8,但在生产机器上运行时,此构建脚本默认为 cp1252(但不是在开发环境中)。超级神秘,直到我们弄清楚发生了什么。

标签: java mysql hibernate utf-8


【解决方案1】:

让我们验证它们是否正确存储...请使用SELECT col, HEX(col) ... 获取一些带有立陶宛字符的单元格。正确存储的ą 将显示C485。其他应显示 C4xx 或 C5xx 的各种十六进制值。 3F?

但是,更重要的是,确实显示了 4 个字符。 Š 应该C5A0 如果正确存储为 utf8。但是,我怀疑您会看到8A,这意味着表中的列确实被声明为CHARACTER SET latin1。 (这 4 个字符出现在 my charset blog 的第一列)。

执行SHOW CREATE TABLE 以查看该列是如何定义的。如果它显示latin1,那么问题出在表定义上,您可能应该重新开始。

【讨论】:

  • 带有 Ogonek (ų) 的拉丁文小写字母 U 应该具有十六进制 C5B3,因此它应该与带有 ogonek 的其他字母相同。
  • 这样做的十六进制看起来像正确的立陶宛字符。我怀疑 ų 是在前一段时间插入的,当时您 something 配置不同。 (注意 Š 通过了。)insert into buildings values (11,'ąĄčČęĘ', 'asda'); 是通过 Hibernate 完成的吗?它似乎已正确存储。
  • 不,我是手动插入的。在当前的开发环境中,每次都会重新创建数据库。
【解决方案2】:

您必须确保参与数据输入的每个组件都明确使用 UTF-8 编码。

  • 如果您通过浏览器输入值,请确保 显示带有以下标题的结果的页面 Content-Type: text/html; charset=utf-8.

  • 输入表单定义如下

    &lt;form action="submit" accept-charset="UTF-8"&gt;...&lt;/form&gt;.

  • 如果您从字节数组创建 String 对象,请确保您 在构造函数中明确声明Charset

  • 如果您的输入来自文本文件,则该文件必须是 UTF-8 编码。

  • 如果直接在您的代码中硬编码,那么源代码必须是 UTF-8 编码。

【讨论】:

    【解决方案3】:

    您的数据库拥有正确的 UTF-8(特殊字母两个或多个字节)这一事实令人放心。

    如果您得到一个 ? 表示特殊字母,则它试图将 UTF-8 转换为不包含这些字母的某些编码。 似乎就是这样正确转换的字母在 ISO-8859-1Windows-1252 范围内。其他人不是。 现在 ISO-88591-1 aka Latin-1 是默认的 HTTP 编码,在 java EE 服务器中是默认的。你可能想在写之前做:

    response.setCharacterEncoding("UTF-8");
    

    现在System.out.println 的一个问题是它使用系统默认编码。使用记录器记录到文件更有趣。或者调试和检查 String 及其 char 数组。

    模式看起来确实有效,可能是模式字符串直接来自 Java 源,并且编辑器编码和 javac 编译器编码不同。这可以通过 u 转义 java 中的字符串文字来检查:"\u0105" 而不是 "ą"

    制作一个单元测试,对数据库进行读写操作。

    【讨论】:

      猜你喜欢
      • 2015-02-20
      • 2018-06-25
      • 2021-04-07
      • 2016-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多