【问题标题】:Can't persist emojis with mysql and hibernate无法使用 mysql 和 hibernate 持久化表情符号
【发布时间】:2014-07-22 11:44:37
【问题描述】:

我实际上在 Stackoverflow 上多次发现这个问题,但解决方案对我没有帮助。

我的 android 应用程序中有一个聊天模块,并希望将消息保存在我的服务器数据库中,这在出现表情符号等特殊字符之前工作正常。

ERROR: Incorrect string value: '\xF0\x9F\x98\x81' for column 'message' at row 1
...
...
Caused by: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x98\x81' for column 'message' at row 1
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1084)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4232)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4164)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2615)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2776)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2838)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2082)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2334)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2262)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2246)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:187)
... 23 more

我的环境是:

-Mysql 5.6
-Tomcat 8.0.8
-Hibernate 4.3.5
-JDK 1.8.0_05

这是带有问题列的使用表,'message':

这些是我在 persistence.xml(2.1 版)中的属性:

<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/gamedb?useUnicode=true&amp;characterEncoding=UTF-8" />
<property name="javax.persistence.jdbc.user" value="*********" />
<property name="javax.persistence.jdbc.password" value="**************" />

<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
<property name="hibernate.connection.useUnicode" value="true" />
<property name="hibernate.connection.characterEncoding" value="utf8" />

现在我尝试了以下解决方案都没有效果:

-Change datatype of 'message' from varchar to longtext
-Change collation of 'message' to utf8mb4
-Change collation of table to utf8mb4
-Append url with "?useUnicode=true&amp;characterEncoding=UTF-8"
-Set character-set-server of mysql to utf8mb4

我认为表情符号已正确传输到服务器,在它保留消息之前将其广播回应用程序并正确显示。

【问题讨论】:

    标签: java mysql hibernate unicode


    【解决方案1】:

    我曾经遇到过同样的问题。我不知道一个很好的解决方案,但这对我有用。

    创建 Session 对象后,我手动更改了连接排序规则:

    s.doReturningWork(new ReturningWork<Object>() {
        @Override
        public Object execute(Connection conn) throws SQLException
        {
            try(Statement stmt = conn.createStatement()) {
                stmt.executeQuery("SET NAMES utf8mb4");
            }
    
            return null;
        }
    });
    

    【讨论】:

      【解决方案2】:

      如果您将 hibernatec3p0 一起使用,则可以使用 c3p0 配置 connectionCustomizerClassName,您可以将其设置为使用连接 c3p0 工作的类得到了。

      示例:

      hibernate.cfg.xml

      <property name="hibernate.c3p0.connectionCustomizerClassName">com.hzmoyan.newlyappserver.db.C3p0UseUtf8mb4</property>
      

      C3p0UseUtf8mb4 类

      public class C3p0UseUtf8mb4 extends  AbstractConnectionCustomizer{
           @Override
          public void onAcquire(Connection c, String parentDataSourceIdentityToken)
              throws Exception {
              super.onAcquire(c, parentDataSourceIdentityToken);
              try(Statement stmt = c.createStatement()) {
                  stmt.executeQuery("SET NAMES utf8mb4");
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        解决办法是use utf8mb4 rather than utf8 in MySQL。我链接到的博客文章解释了如何做到这一点。

        【讨论】:

        • 除了第 5 步中的“SET NAMES”部分外,我都遵循了每个步骤,因为我使用 javax.persistence.EntityManagerFactory 而不是休眠替代方案,因此不使用任何语句查询。我更改了 url,使其具有 utf8mb4 而不是 utf8,并添加了带有 utf8mb4 的 hibernate.connection.CharSet,但是 .characterEncoding 值不能从 utf8 更改为 utf8mb4 而不会出现错误。我是否必须为此使用 Hibernate 会话管理而不是我现在拥有的?
        • 最好通过从该博客文章中提取相关信息来改进这一点,以防出现 404。
        【解决方案4】:

        我刚刚发现了一个不错的小技巧,无需添加任何代码即可使其工作。如果您将验证查询设置为 SET NAMES utf8mb4,那么它将在获取连接时执行此操作,因此每次检索新连接时都设置参数。您还需要对借用进行测试才能完成这项工作。

        请注意,我发现这有时可能需要几秒钟才能在重新启动后工作,因此如果您有等待在启动时处理的记录,则可能会出现故障

        因此,在您的 application.properties 中,您可以添加类似

        的内容
        datasource.test-on-borrow=true
        datasource.validation-query=SET NAMES utf8mb4
        

        【讨论】:

          【解决方案5】:

          我能够通过在我的连接 URL 中提供以下内容来解决此问题;

          useUnicode=true&characterEncoding=UTF-8

          示例;

          jdbc:mysql://localhost/database?useUnicode=true&characterEncoding=UTF-8
          

          【讨论】:

            【解决方案6】:

            也许你需要修改hibernate配置为

            <property name="hibernate.connection.characterEncoding" value="utf8mb4" />
            

            【讨论】:

              【解决方案7】:

              如果你的数据源是org.apache.commons.dbcp.BasicDataSource你可以设置connectionInitSqls参数

                  <bean id="dataSource"
                        class="org.apache.commons.dbcp.BasicDataSource"
                        p:driverClassName="${jdbc.driverClassName}"
                        p:url="${jdbc.databaseurl}"
                        p:username="${jdbc.username}"
                        p:password="${jdbc.password}"
                        p:testOnBorrow="true"
                        p:maxActive="1000"
                        p:testWhileIdle="true"
                        p:validationQuery="SELECT 1"
                        p:validationQueryTimeout="5">
              
                      <property name="connectionInitSqls">
                          <list>
                              <value>SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci'</value>
                          </list>
                      </property>
              
                  </bean>
              

              【讨论】:

                【解决方案8】:

                在没有收到我的 cmets 的进一步答案后,我找到了一个替代解决方案:Base64。

                我没有教我的数据库理解 utf8mb4,而是在存储它们之前将所有关键消息编码为 Base64,并在从数据库中检索它们时对其进行解码。

                专业版:
                - 效果很好
                - 已经为 java 和 android 提供了库

                相反:
                - Base64 字符串比纯 utf8mb4 字符串占用更多空间(多 33%-36%)
                - 可能会消耗一些性能编码和解码

                【讨论】:

                • 是的,gl 搜索或订购
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2015-08-21
                • 2021-03-18
                • 2011-05-12
                • 2010-09-24
                • 1970-01-01
                • 2010-11-24
                • 1970-01-01
                相关资源
                最近更新 更多