最近使用mysql做一个交易网站,使用hibernate作为持久化框架。
当我使用hibernate的Order进行排序的时候,杯具发生了。中文给我乱排了。
mysql中如果需要正常按照中文排序,其中一种处理方法是
SELECT * FROM BZ_COMPANY ORDER BY CONVERT( COMPANY_NAME USING GBK ) ASC
可问题是这样就脱离hibernate了。本打算使用QBC做一些公共的方法的。
然后就去看了下hibernate中Order的实现。
hibernate的Order:
//$Id: Order.java,v 1.1 2011/05/29 18:11:15 Surui Exp $ package org.hibernate.criterion; import java.io.Serializable; import java.sql.Types; import org.hibernate.Criteria; import org.hibernate.HibernateException; import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.type.Type; /** * Represents an order imposed upon a <tt>Criteria</tt> result set * @author Gavin King */ public class Order implements Serializable { private boolean ascending; private boolean ignoreCase; private String propertyName; public String toString() { return propertyName + ' ' + (ascending?"asc":"desc"); } public Order ignoreCase() { ignoreCase = true; return this; } /** * Constructor for Order. */ protected Order(String propertyName, boolean ascending) { this.propertyName = propertyName; this.ascending = ascending; } /** * Render the SQL fragment * */ public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException { String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName); Type type = criteriaQuery.getTypeUsingProjection(criteria, propertyName); StringBuffer fragment = new StringBuffer(); for ( int i=0; i<columns.length; i++ ) { SessionFactoryImplementor factory = criteriaQuery.getFactory(); boolean lower = ignoreCase && type.sqlTypes( factory )[i]==Types.VARCHAR; if (lower) { fragment.append( factory.getDialect().getLowercaseFunction() ) .append('('); } fragment.append( columns[i] ); if (lower) fragment.append(')'); fragment.append( ascending ? " asc" : " desc" ); if ( i<columns.length-1 ) fragment.append(", "); } return fragment.toString(); } /** * Ascending order * * @param propertyName * @return Order */ public static Order asc(String propertyName) { return new Order(propertyName, true); } /** * Descending order * * @param propertyName * @return Order */ public static Order desc(String propertyName) { return new Order(propertyName, false); } }
重点就在toSqlString上了,QBC的Criteria也是toSqlString产生对应sql的,所以只要在这里做手脚,就能达到效果。
当然,不赞成直接改源码。
然后就有了GBKOrder:
package comm; import java.sql.Types; import org.hibernate.Criteria; import org.hibernate.HibernateException; import org.hibernate.criterion.CriteriaQuery; import org.hibernate.criterion.Order; import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.type.Type; public class GBKOrder extends Order { private String encoding = "GBK"; private boolean ascending; private boolean ignoreCase; private String propertyName; @Override public String toString() { return "CONVERT( " + propertyName + " USING " + encoding + " ) " + (ascending ? "asc" : "desc"); } @Override public Order ignoreCase() { ignoreCase = true; return this; } /** * Constructor for Order. */ protected GBKOrder(String propertyName, boolean ascending) { super(propertyName, ascending); this.propertyName = propertyName; this.ascending = ascending; } /** * Constructor for Order. */ protected GBKOrder(String propertyName, String dir) { super(propertyName, dir.equalsIgnoreCase("ASC") ? true : false); ascending = dir.equalsIgnoreCase("ASC") ? true : false; this.propertyName = propertyName; this.ascending = ascending; } /** * Render the SQL fragment * */ @Override public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException { String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName); Type type = criteriaQuery.getTypeUsingProjection(criteria, propertyName); StringBuffer fragment = new StringBuffer(); for (int i = 0; i < columns.length; i++) { SessionFactoryImplementor factory = criteriaQuery.getFactory(); boolean lower = ignoreCase && type.sqlTypes(factory)[i] == Types.VARCHAR; if (lower) { fragment.append(factory.getDialect().getLowercaseFunction()).append('('); } fragment.append("CONVERT( " + columns[i] + " USING " + encoding + " )"); if (lower) fragment.append(')'); fragment.append(ascending ? " asc" : " desc"); if (i < columns.length - 1) fragment.append(", "); } return fragment.toString(); } /** * Ascending order * * @param propertyName * @return Order */ public static Order asc(String propertyName) { return new GBKOrder(propertyName, true); } /** * Descending order * * @param propertyName * @return Order */ public static Order desc(String propertyName) { return new GBKOrder(propertyName, false); } }