You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate查询MySQL报binary转utf8mb3转换失败问题求助

问题根因

报错里的\xAC\xED\x00\x05是Java原生序列化流的固定魔数,出现这个错误是两个问题叠加导致:

  • JDBC连接串没有显式指定字符集,驱动建立连接时自动协商字符集出现偏差,触发了二进制类型到utf8mb3的隐式转换逻辑
  • UNION查询关联的表字符集不统一:你只确认了employee_tracking表是utf8mb4,但没有检查关联的contract、contract_extension表的字符集,UNION合并结果集时会选择两部分查询里优先级最低的字符集(也就是utf8mb3)做统一转换,加上Hibernate原生SQL映射时如果识别到列类型不匹配,会把字段值序列化后传输,刚好命中字符集转换逻辑抛出错误。
排查步骤
  • 先查两张关联表的字符集,执行以下SQL,大概率其中某张表或者表内的字符串字段是utf8mb3编码:
SELECT 
  T.table_name,
  CCSA.character_set_name 
FROM information_schema.`TABLES` T, 
information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY` CCSA
WHERE CCSA.collation_name = T.table_collation 
AND T.table_schema = "lambda" 
AND T.table_name IN ('contract', 'contract_extension');
  • 检查当前使用的mysql-connector-java版本,8.0.27版本的MySQL服务端如果配套的驱动版本低于8.0.26,存在UNION查询结果集字符集识别错误的已知bug
  • 打开Hibernate的SQL打印和参数绑定日志,确认最终生成的SQL语句、绑定参数是否存在异常序列化的情况
解决方案

按以下顺序操作即可解决:

  1. 修改JDBC连接URL,显式指定连接使用Unicode和utf8编码,修改后连接串如下:
jdbc:mysql://localhost:3306/lambda?jdbcCompliantTruncation=false&serverTimezone=Europe/Berlin&allowPublicKeyRetrieval=true&useSSL=false&zeroDateTimeBehavior=round&characterEncoding=utf8&useUnicode=true

注意:MySQL Connector/J 8.x版本中,characterEncoding=utf8会自动映射为utf8mb4,不需要手动写utf8mb4,否则可能触发参数识别错误
2. 统一数据库、所有关联表的字符集为utf8mb4,排序规则统一用utf8mb4_0900_ai_ci,彻底避免UNION合并时的隐式字符集转换:

-- 修改库级默认字符集
ALTER DATABASE lambda CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci;
-- 如果上一步查到两张关联表不是utf8mb4,执行以下语句修改
ALTER TABLE contract CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
ALTER TABLE contract_extension CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
  1. 调整原生SQL写法:去掉*通配符查询,显式列出所有需要返回的列,保证UNION两部分查询返回的列数量、类型完全一致;如果不需要去重,把UNION换成UNION ALL,减少不必要的排序去重操作带来的类型转换。参考修改后的代码:
StringBuilder sqlQuery = new StringBuilder("SELECT this_.id as id, this_.number_of_hours as number_of_hours, this_.date_start as date_start, this_.date_end as date_end, this_.date_created as date_created, this_.obsolete as obsolete FROM (");
sqlQuery.append(" select tt.id, tt.number_of_hours, tt.date_start, tt.date_end, tt.date_created, tt.obsolete from employee_tracking tt ")
        .append(" inner join contract c on tt.contract_id=c.id ")
        .append(" where tt.obsolete = :OBSOLETE ");
    
// 无去重需求时用UNION ALL,性能更好也能减少类型转换问题
sqlQuery.append(" UNION ALL ");

sqlQuery.append(" select tt_.id, tt_.number_of_hours, tt_.date_start, tt_.date_end, tt_.date_created, tt_.obsolete from employee_tracking tt_ ")
        .append(" inner join contract_extension ce_ on tt_.contract_extension_id=ce_.id ")
        .append(" where tt_.obsolete = :OBSOLETE ");
    
sqlQuery.append(") AS this_ ORDER BY id ASC ");


SQLQuery query = getSessionFactory().getCurrentSession().createSQLQuery(sqlQuery.toString());
query.setParameter("OBSOLETE", 0);
    
query.addEntity(EmployeeTracking.class);

List lst = query.list();
  1. 如果以上操作后仍报错,检查EmployeeTracking实体类:确认所有字段类型和数据库字段类型一一对应,不要出现数据库是varchar/int等基础类型、实体类字段定义为Object/Blob等通用类型的情况,避免Hibernate识别类型失败时对字段做序列化处理。

内容的提问来源于stack exchange,提问作者javaistaucheineinsel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 10:36:24