在使用 Hibernate 搭配 MySQL 開發時,許多開發者都會遇到中文排序失效的問題。MySQL 預設的排序規則無法正確處理中文字符,導致查詢結果順序不符合預期。雖然 MySQL 後續推出了 utf8_unicode_ci 等排序規則,但在追求跨資料庫兼容且不修改業務代碼的場景下,我們需要在 Hibernate 層面解決這個問題。本文介紹兩種在 Hibernate 中實現中文排序的方案。
通過繼承 MySQLDialect 並註冊一個名為 convert_gbk 的 SQL 函數,在 HQL 的 ORDER BY 子句中調用該函數,將字段轉換為 GBK 編碼後再排序。
public class MySQLExtendDialect extends MySQLDialect {
public MySQLExtendDialect() {
super();
registerFunction("convert_gbk",
new SQLFunctionTemplate(Hibernate.STRING, "convert(?1 using gbk)"));
}
}
使用方式: 在 HQL 中將 ORDER BY field 改為 ORDER BY convert_gbk(field)。
缺點: 需要修改所有涉及中文排序的 HQL 語句,且不同資料庫需要編寫對應的方言擴展類,維護成本較高。
繼承 MySQLDialect 並重寫 renderOrderByElement 方法,在生成 SQL 時自動為排序字段包裝 CONVERT(... USING gbk),業務代碼完全無感知。
public class MySQLGBKDialect extends MySQLDialect {
@Override
public String renderOrderByElement(String expression, String collation,
String order, NullPrecedence nulls) {
expression = "convert(" + expression + " using 'gbk')";
return super.renderOrderByElement(expression, collation, order, nulls);
}
}
優點: 不需修改任何 HQL 或 Java 代碼,只需在 Hibernate 配置中指定該方言類即可,實現真正的跨資料庫零侵入。
缺點: 所有的 ORDER BY 操作都會執行 CONVERT,可能對非中文字段的排序性能產生微小影響。
在 hibernate.cfg.xml 或 Spring 配置中設置方言:
<property name="hibernate.dialect">com.yourpackage.MySQLGBKDialect</property>
方案二更適合追求代碼零侵入、快速接入的項目;方案一則適合需要精細控制哪些字段進行中文排序的場景。根據項目實際需求選擇即可。