【问题标题】:Java EE, Hibernate, MySql UTF-8 query doesn't workJava EE、Hibernate、MySql UTF-8 查询不起作用
【发布时间】:2017-07-11 06:28:18
【问题描述】:

所以我已经用 Wildfly 和 MySql 设置了休眠。

查询有效,但查询 UTF-8 字符名称时出现问题。

在 MySql 上:

SELECT * FROM users WHERE firstname = "ნიკა";

不会导致空集。

在java中:

Session session = HibernateUtils.getSession();

String name = request.getParameter("name");

CriteriaBuilder builder = session.getCriteriaBuilder();

CriteriaQuery<UsersEntity> query = builder.createQuery(UsersEntity.class);
Root<UsersEntity> usersRoot = query.from(UsersEntity.class);
query.select(usersRoot)
        .where(builder.equal(usersRoot.get("firstname"), name));

List<UsersEntity> list = session.createQuery(query).list();

session.close();

writeUsers(list, response.getWriter());

查询localhost:8080/main?name=ნიკა时结果为空集

我该如何解决这个问题?

更新:

我在查询所有数据并显示它们时也有问题 非英文字符替换为问号。

更新 2:

此代码导致浏览器上显示问号:

response.getWriter().write("ნიკა ჩხარტიშვილი");

虽然这个工作正常:

response.setCharacterEncoding("UTF-8");
response.getWriter().write("ნიკა ჩხარტიშვილი");

当使用此查询SELECT * FROM users WHERE username='ნიკა' 查询数据库时,数据库会收到问号而不是ნიკა(这就是在wireshark 中显示的内容)。

我认为这是野蝇问题,因为它正确接收了 UTF-8,但除非指定发送 UTF-8,否则会发送问号。

【问题讨论】:

  • 如果为了测试您可以在代码中硬编码名称,它是否也有效。如果是这样,那就是浏览器完成的翻译。
  • @davejal 硬编码也不行。
  • 您的 SQL 示例使用 firstname = "ნიკა"。您的 URL 示例使用 localhost:8080/main?name=ნიკა。如果您在调用 writeUsers 后关闭会话会发生什么情况? writeUsers 调用有什么作用?
  • 它只是将名称输出到response.getWriter()中,不能这样,因为localhost:8080/main?name=dato可以正常工作。

标签: java mysql hibernate utf-8 wildfly


【解决方案1】:

以下是要启用 UTF8 编码的常见位置

1) 确保使用字符集 utf8 和排序规则 utf8_unicode_ci

创建数据库及其表

2)hibernate配置文件下

<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/DATABASE_NAME?useUnicode=true&amp;characterEncoding=UTF-8</property>
<property name="hibernate.connection.CharSet">utf8</property>
<property name="hibernate.connection.characterEncoding">utf8</property>
<property name="hibernate.connection.useUnicode">true</property>

3) 在主html模板标题部分下

<meta http-equiv="content-type" content="text/html;charset=UTF-8" />

4) apache tomcat server.xml下

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>

【讨论】:

    【解决方案2】:

    您可以使用 Hibernate @Type 属性,根据您的要求,您可以自定义注释并应用在字段之上。 喜欢:

    public class PhoneNumberType implements UserType {
    @Override
    public int[] sqlTypes() {
        return new int[]{Types.INTEGER, Types.INTEGER, Types.INTEGER};
    }
    
    @Override
    public Class returnedClass() {
        return PhoneNumber.class;
    }
    
    // other methods
    }   
    

    一、空SafeGet方法:

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, 
    SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException {
    int countryCode = rs.getInt(names[0]);
     if (rs.wasNull())
        return null;
     int cityCode = rs.getInt(names[1]);
    int number = rs.getInt(names[2]);
    PhoneNumber employeeNumber = new PhoneNumber(countryCode, cityCode, number);
     return employeeNumber;
     }
    

    接下来,null SafeSet 方法:

    @Override
     public void nullSafeSet(PreparedStatement st, Object value, 
      int index, SharedSessionContractImplementor session) 
       throws HibernateException, SQLException {
        if (Objects.isNull(value)) {
        st.setNull(index, Types.INTEGER);
        } else {
        PhoneNumber employeeNumber = (PhoneNumber) value;
        st.setInt(index,employeeNumber.getCountryCode());
        st.setInt(index+1,employeeNumber.getCityCode());
        st.setInt(index+2,employeeNumber.getNumber());
      }
     }
    

    最后,我们可以在我们的 OfficeEmployee 实体类中声明我们自定义的 PhoneNumberType:

    @Entity
    @Table(name = "OfficeEmployee")
     public class OfficeEmployee {
    
      @Columns(columns = { @Column(name = "country_code"), 
      @Column(name = "city_code"), @Column(name = "number") })
      @Type(type = "com.baeldung.hibernate.customtypes.PhoneNumberType")
       private PhoneNumber employeeNumber;
    
     // other fields and methods
      }
    

    这可能会解决您的问题,这将适用于所有数据库。 如果您想了解更多信息,请参考:: https://www.baeldung.com/hibernate-custom-types

    【讨论】:

      【解决方案3】:

      我修好了。

      与客户端的第一次连接不是UTF-8。 修复它:

      response.setCharacterEncoding("UTF-8");
      

      这适用于一个 servlet。 将 wildflystandalone.xml 配置文件更新为

      <servlet-container name="default" default-encoding="UTF-8">
          <jsp-config/>
          <websockets/>
      </servlet-container>
      

      default-encoding 属性添加到servlet-container,现在每个响应都将具有默认的UTF-8 编码。

      JDBC 通信不是UTF-8

      修复更新connection.url,附加

      ?useUnicode=yes&amp;amp;characterEncoding=UTF-8 最后。

      <property name="connection.url">jdbc:mysql://localhost:3306/cnick?useUnicode=yes&amp;characterEncoding=UTF-8</property>
      

      上次我这样做时,我认为它不起作用,因为我查询的内容不在数据库中。现在它正在工作。

      【讨论】:

        【解决方案4】:

        如果在从 MySQL 数据库读取时遇到问号,请参阅 here

        • 要存储的字节未编码为 utf8/utf8mb4。解决这个问题。
        • 数据库中的列是CHARACTER SET utf8(或utf8mb4)。解决这个问题。
        • 另外,请检查读取期间的连接是否为 UTF-8。

        问号是在INSERTing到数据库时产生的,所以无法恢复原文。

        我很确定任何提及"ISO-8859-1" 的内容都是错误的。 %E1%83%9C 的网址编码。获取name 应该为您撤消该操作,您无需执行任何操作。因此,执行getBytes("ISO-8859-1") 要求在该编码中提供ნიკა。但该编码仅涵盖西欧。我建议尝试

        new String(request.getParameter("name").getBytes("UTF-8"));
        

        (那是 Java 吗?还是什么?)

        【讨论】:

        • 当我从命令行选择时,不存在问号。并且使用 where 子句进行选择可以正常工作。我认为这一定是连接问题。
        • 我刚刚检查了另一件事。我在服务器上记录了名称,它们被正确编码,但是在发送到浏览器时,它们被打上了问号。
        • 没有从 MySQL 到浏览器的 直接 连接。它必须通过某个应用程序,并且该应用程序必须需要修复。
        • 它不起作用。文字或编码服务器向 mysql 发送带有问号的查询。如何确保与数据库的连接使用 UTF-8?
        • 在他们的链接中查看“最佳实践”。
        【解决方案5】:

        这是因为 URL 只能使用 ASCII 字符集通过 Internet 发送。

        如果您对服务器的调用来自 javascript,则应使用 encodeURIComponent("ნიკა") 对您的名称值进行编码,您的调用应如下所示:

        localhost:8080/main?name=%E1%83%9C%E1%83%98%E1%83%99%E1%83%90
        

        如果您只是将 URL 粘贴到浏览器中,请照常进行

        localhost:8080/main?name=ნიკა
        

        然后在您从请求中获取名称值后,在您的服务器中再次将其编码为 UTF-8,如下所示:

         //String name = request.getParameter("name");
         String name = new String(request.getParameter("name").getBytes("ISO-8859-1"), "UTF-8");
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-03-21
          • 2015-12-05
          • 2015-02-16
          • 2011-11-26
          • 1970-01-01
          • 2015-02-22
          • 1970-01-01
          相关资源
          最近更新 更多