【问题标题】:java.sql.SQLException: Incorrect string value: '\xF0\x9F\x91\xBD\xF0\x9F...'java.sql.SQLException:不正确的字符串值:'\xF0\x9F\x91\xBD\xF0\x9F...'
【发布时间】:2012-11-19 04:12:19
【问题描述】:

我有以下字符串值:“walmart obama ????????”

我正在使用 MySQL 和 Java。

我收到以下异常:`java.sql.SQLException: Incorrect string value: '\xF0\x9F\x91\xBD\xF0\x9F...'

这是我要插入的变量:

var1 varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL`

我的 Java 代码试图插入“walmart obama ????????”是一个preparedStatement。所以我使用的是setString() 方法。

看起来问题是值的编码??????????。我怎样才能解决这个问题?以前我使用的是 Derby SQL 和值 ??????????只是最终变成了两个正方形(我认为这是空字符的表示)

非常感谢所有帮助!

【问题讨论】:

  • 创建数据库时,可以这样给出字符集和排序规则:CREATE DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

标签: java mysql encoding character-encoding sqlexception


【解决方案1】:

您拥有的是 EXTRATERRESTRIAL ALIEN (U+1F47D)BROKEN HEART (U+1F494) 不在基本的多语言平面上。它们甚至不能在 java 中表示为一个字符,"??".length() == 4。它们绝对不是空字符,如果您不使用支持它们的字体,就会看到方块。

MySQL's utf8 only supports basic multilingual plane, and you need to use utf8mb4 instead:

对于补充字符,utf8根本无法存储字符, 而 utf8mb4 需要四个字节来存储它。由于 utf8 无法存储 字符,你没有任何补充字符 utf8 列,您不必担心转换字符或 从旧版本的 MySQL 升级 utf8 数据时丢失数据。

所以要支持这些字符,你的 MySQL 需要 5.5+ 并且你需要在任何地方使用utf8mb4。连接编码需要为utf8mb4,字符集需要为utf8mb4,排序需要为utf8mb4。对于java来说还是"utf-8",但是MySQL需要区分一下。

我不知道您使用的是什么驱动程序,但设置连接字符集的与驱动程序无关的方法是发送查询:

SET NAMES 'utf8mb4'

在建立连接之后。

See also this for Connector/J:

14.14:如何将 4 字节 UTF8、utf8mb4 与 Connector/J 一起使用?

要将 4 字节 UTF8 与 Connector/J 一起使用,请将 MySQL 服务器配置为 character_set_server=utf8mb4。然后连接器/J 将使用该设置 只要在连接中设置 characterEncoding 字符串。这相当于自动检测字符集。

同时调整列和数据库:

var1 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL

同样,您的 MySQL 版本需要相对最新才能支持 utf8mb4。

【讨论】:

  • 查看我的其他相关帖子:stackoverflow.com/questions/13748170/…。如果你能回答它,那么你也已经回答了这个问题。另一篇文章有​​更多关于我所做的事情的详细信息。
  • @CodeKingPlusPlus 您是否将数据库中的所有内容都更改为utf8mb4,看来您仍在使用utf8_general_ci..
  • 不要对 Connector/J 进行“SET NAMES”:dev.mysql.com/doc/connector-j/en/…Do not issue the query set names with Connector/J, as the driver will not detect that the character set has changed, and will continue to use the character set detected during the initial connection setup.
  • 如果您只想摆脱 BMP 外部的字符而不是处理更改数据库的混乱,请参见此处:stackoverflow.com/questions/4035562/…
  • 我也有同样的问题,按照上面的步骤操作,但是直到更改了 C:\ProgramData\MySQL\MySQL Server 5.7\my.ini 中的 character-set-server=utf8mb4 才得到解决
【解决方案2】:

奇怪的是,我发现从 JDBC url 中删除 &characterEncoding=UTF-8 可以解决类似问题。

根据我的属性,

jdbc_url=jdbc:mysql://localhost:3306/dbName?useUnicode=true

我认为这支持 @Esailija 上面所说的,即我的 MySQL,它确实是 5.5,正在找出它自己最喜欢的 UTF-8 编码风格。

(注意,我还在 java 代码中指定了 InputStream 我正在读取的 UTF-8,这可能不会造成伤害)...

【讨论】:

  • 也许 useUnicode=true 甚至不需要?在我的情况下,唯一有效的是在服务器上全局设置character_set_server=utf8mb4(RDS 参数组)并且 NOT 在 JDBC URL 中有任何字符编码。
【解决方案3】:

总而言之,要保存需要 4 个字节的符号,您需要更新 utf8mb4 的字符集和排序规则:

  1. 数据库表/列: alter table <some_table> convert to character set utf8mb4 collate utf8mb4_unicode_ci
  2. 数据库服务器连接 (see)

在#2 的开发环境中,我更喜欢在启动服务器时在命令行上设置参数: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci


顺便说一句,注意Connector/J behaviorSET NAMES 'utf8mb4'

不要使用 Connector/J 发出查询集名称,因为驱动程序不会检测到字符集已更改,并将继续使用在初始连接设置期间检测到的字符集。

并避免在连接 url 中设置 characterEncoding 参数,因为它会覆盖配置的服务器编码:

要覆盖客户端自动检测到的编码,请在用于连接到服务器的 URL 中使用 characterEncoding 属性。

【讨论】:

    【解决方案4】:

    我是如何解决我的问题的。

    我有

    ?useUnicode=true&characterEncoding=UTF-8
    

    在我的hibernate jdbc连接url中,我将数据库中的字符串数据类型更改为longtext,之前是varchar。

    【讨论】:

    • 如果您不需要索引该列并且它相对较小,但我可以为我的所有列做这个技巧
    【解决方案5】:

    我遇到了同样的问题,并通过将每一列的 Collat​​ion 设置为 utf8_general_ci 来解决它。

    【讨论】:

      【解决方案6】:

      useUnicode=true&characterEncoding=UTF-8 行附加到您的 jdbc url。

      在您的情况下,数据不是使用UTF-8 编码发送的。

      【讨论】:

      • 我如何附加这个?在我的连接字符串中?如果有帮助,我正在使用 Netbeans。
      • 你是如何建立连接的?
      • DriverManager.getConnection("jdbc:mysql://localhost:####/[dbName]", [用户名], [密码]);
      • 这样做 - DriverManager.getConnection("jdbc:mysql://localhost:####/[dbName]?useUnicode=true&characterEncoding=UTF-8", [用户名] , [密码]);
      • 从头开始,我忘记了“?”但是现在我又回到了与原始帖子相同的错误...
      【解决方案7】:

      我猜 MySQL 不相信这是有效的 UTF8 文本。我尝试在具有相同列定义的测试表上插入(mysql 客户端连接也是 UTF8),虽然它进行了插入,但我使用 MySQL CLI 客户端和 JDBC 检索的数据没有正确检索值。为了确保 UTF8 能正常工作,我为 obama 插入了“ö”而不是“o”:

      johan@maiden:~$ mysql -vvv test < insert.sql 
      --------------
      insert into utf8_test values(_utf8 "walmart öbama ??")
      --------------
      
      Query OK, 1 row affected, 1 warning (0.12 sec)
      
      johan@maiden:~$ file insert.sql 
      insert.sql: UTF-8 Unicode text
      

      用于测试的小型 java 应用程序:

      package test.sql;
      
      import java.sql.Connection;
      import java.sql.DriverManager;
      import java.sql.PreparedStatement;
      import java.sql.ResultSet;
      
      public class Test
      {
      
          public static void main(String[] args)
          {
              System.out.println("test string=" + "walmart öbama ??");
              String url = "jdbc:mysql://hostname/test?useUnicode=true&characterEncoding=UTF-8";
              try
              {
                  Class.forName("com.mysql.jdbc.Driver").newInstance();
                  Connection c = DriverManager.getConnection(url, "username", "password");
                  PreparedStatement p = c.prepareStatement("select * from utf8_test");
                  p.execute();
                  ResultSet rs = p.getResultSet();
                  while (!rs.isLast())
                  {
                      rs.next();
                      String retrieved = rs.getString(1);
                      System.out.println("retrieved=\"" + retrieved + "\"");
      
                  }
              }
              catch (Exception e)
              {
                  e.printStackTrace();
              }
          }
      
      }
      

      输出:

      johan@appel:~/workspaces/java/javatest/bin$ java test.sql.Test
      test string=walmart öbama ??
      retrieved="walmart öbama "
      

      另外,我已经尝试使用 JDBC 连接进行相同的插入操作,但它引发了与您遇到的相同的异常。 我相信这是一个 MySQL 错误。也许已经有关于这种情况的错误报告..

      【讨论】:

      • 顺便说一句,您的字符串中的字符甚至在 OSX 上的 Firefox 和 Chrome 中都无法正确显示。它们确实在我的 iTerm 应用程序中正确显示。我认为这取决于字体。
      【解决方案8】:

      我遇到了同样的问题,在仔细检查所有字符集并发现它们都很好之后,我意识到我在课堂上的错误属性被注释为 @Column 而不是 @JoinColumn (javax.presistence; hibernate),它正在破坏一切。

      【讨论】:

        【解决方案9】:

        此设置 useOldUTF8Behavior=true 对我来说效果很好。它没有给出不正确的字符串错误,而是将 Ã 等特殊字符转换为多个字符并保存在数据库中。

        为了避免这种情况,我从 JDBC 参数中删除了这个属性,而是将我的列的数据类型转换为 BLOB。这很完美。

        【讨论】:

        • 您能否在答案中添加更多细节? (代码、命令等)
        【解决方案10】:

        执行

        show VARIABLES like "%char%”;
        

        如果不是 utf8mb4,则查找字符集服务器。

        在你的 my.cnf 中设置它,比如

        vim /etc/my.cnf
        

        添加一行

        character_set_server = utf8mb4
        

        最后重启mysql

        【讨论】:

        • character_set_server 是选项,而不是 character-set-server
        【解决方案11】:

        此外,数据类型可以使用varchar或text的blob安装。

        【讨论】:

        • 你不想这样
        猜你喜欢
        • 2013-12-23
        • 1970-01-01
        • 2020-02-20
        • 2015-01-24
        • 1970-01-01
        • 2014-07-03
        • 2019-05-27
        • 2018-05-05
        相关资源
        最近更新 更多