`
Kenny.Lee
  • 浏览: 514642 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Hibernate查询中实现order by的 NULLS LAST 和 NULLS FIRST

阅读更多

在不同数据库中对null字段的order by优先级有所不同,造成在一些情况下应用的排序有误。解决办法其实可以使用NULLS LAST和 NULLS FIRST来声明给数据库对NULL字段的排序,但在使用hibernate的条件查询(criteria)不支持这一特性。不过直到4.2.0.CR1,hibernate官方解决了这个问题。详细见:https://hibernate.onjira.com/browse/HHH-465

 

虽然官方已经解决了这个问题,但之前对此问题的一个的解决方案很值得参考,可能在日后解决问题的时候得到一定的启发。这个方案简单来说,就是在生成的SQL后,添加为SQL增加自定义的修改,所以十分日后也许十分有用。

 

参考 http://stackoverflow.com/questions/3683174/hibernate-order-by-with-nulls-last

 

1.创建一个自己的Interceptor,MyNullsFirstInterceptor

 

 

public class MyNullsFirstInterceptor extends EmptyInterceptor {
	private static final long serialVersionUID = -8690066766867444573L;
	private final Log logger = LogFactory.getLog(getClass());

	private static final String ORDER_BY_TOKEN = "order by";

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.hibernate.EmptyInterceptor#onPrepareStatement(java.lang.String)
	 */
	//FIXME replace来解决不完美。并且如果没写ASC或者DESC的情况下,也会有默认的排序。
	public String onPrepareStatement(String sql) {

		int orderByStart = sql.toLowerCase().indexOf(ORDER_BY_TOKEN);
		boolean isNeedFixNullFirst = orderByStart > -1;
		if (!isNeedFixNullFirst) {
			return super.onPrepareStatement(sql);
		}

		sql = StringUtils.replace(sql, " DESC ", " DESC NULLS LAST ");
		sql = StringUtils.replace(sql, " DESC)", " DESC NULLS LAST)");
		sql = StringUtils.replace(sql, " ASC ", " ASC NULLS FIRST ");
		sql = StringUtils.replace(sql, " ASC)", " ASC NULLS FIRST)");

		// orderByStart += ORDER_BY_TOKEN.length() + 1;
		// int orderByEnd = sql.indexOf(")", orderByStart);
		// if (orderByEnd == -1) {
		// orderByEnd = sql.indexOf(" UNION ", orderByStart);
		// if (orderByEnd == -1) {
		// orderByEnd = sql.length();
		// }
		// }
		// String orderByContent = sql.substring(orderByStart, orderByEnd);
		// String[] orderByNames = orderByContent.split("\\,");
		// for (int i = 0; i < orderByNames.length; i++) {
		// if (orderByNames[i].trim().length() > 0) {
		// if (orderByNames[i].trim().toLowerCase().endsWith("desc")) {
		// orderByNames[i] += " NULLS LAST";
		// } else {
		// orderByNames[i] += " NULLS FIRST";
		// }
		// }
		// }
		// orderByContent = StringUtils.join(orderByNames, ",");
		// sql = sql.substring(0, orderByStart) + orderByContent
		// + sql.substring(orderByEnd);
		logger.debug("--------------------");
		logger.debug(sql);
		logger.debug("--------------------");
		return super.onPrepareStatement(sql);
	}

 

 

注释掉的部分为原帖的解决方案,但使用后发现会报错,没详细的排查,而是采取了简单的处理方案,即看到DESC的时候直接后面添加NULLS LAST,而遇到ASC的时候反之。当然replace的那代码块一段完全可以更好的正则来实现。

 

也可以看到FIXME的那个注释,如果没写ASC和DESC的话,这个就完全起效没用了,但如果用criteria条件查询的话,一定会有的咯。

 

二,添加MyNullsFirstInterceptor到sessionFactory的xml配置内容中。

 

		<property name="entityInterceptor">
			<bean id="myNullsFirstInterceptor"
				class="cn.com.timekey.commons.dao.MyNullsFirstInterceptor" />
		</property>

 

详细如:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
				http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${jdbc.driver}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
	</bean>
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		<property name="hibernateProperties">
			<props>
				<!-- c3p0 ConnectPool Config begin -->
				<prop key="hibernate.connection.provider_class">
					org.hibernate.connection.C3P0ConnectionProvider
				</prop>
				<prop key="hibernate.c3p0.minPoolSize">5</prop>
				<prop key="hibernate.c3p0.maxPoolSize">20</prop>
				<prop key="hibernate.c3p0.timeout">600</prop>
				<prop key="hibernate.c3p0.max_statement">100</prop>
				<prop key="hibernate.c3p0.acquire_increment">2</prop>
				<prop key="hibernate.c3p0.idle_test_period">120</prop>
				<prop key="hibernate.c3p0.validate">false</prop>
				<prop key="hibernate.c3p0.testConnectionOnCheckout">
					false
				</prop>
				<prop key="hibernate.dialect">${jdbc.dialect}</prop>
				<!-- c3p0 ConnectionPool Config end -->
				<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>

				<!-- Take care of this config, affect to DB. -->
				<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
				<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
				<prop key="hibernate.jdbc.fetch_size">50</prop>
				<prop key="hibernate.jdbc.batch_size">30</prop>
				<prop key="hibernate.statement_cache.size">25</prop>
			</props>
		</property>
		<property name="mappingLocations">
			<list>
				<value>
					classpath:/cn/com/timekey/project/po/**.hbm.xml
				</value>
			</list>
		</property>
		<property name="entityInterceptor">
			<bean id="myNullsFirstInterceptor"
				class="cn.com.timekey.commons.dao.MyNullsFirstInterceptor" />
		</property>
	</bean>
</beans>

 

由于这个问题已经在hibernate4.2.0cr1中被修复了。所以也不打算进一步的优化了,至少目前是这么想。这套东西可以作为oracle和db2环境下的临时应急方案吧。(注,因为下mysql,mssql的null字段优先级默认就是最低)

 

分享到:
评论
1 楼 geosmart 2014-07-14  
升级hibernate代价太大,采用楼主的方案,拦截器的确起作用了,谢谢!

相关推荐

    rust-sortStringToSql:锈版。 将排序表达式转换为可在 'ORDER BY' 语句中使用的 SQL,例如 '-aired,id' -> 'aird DESC NULLS LAST, id ASC NULLS LAST'

    将字符串排序为 SQL 这是一个 rust crate,用于将“排序表达式”转换为可在“ORDER BY”中使用的 SQL 表达式。 例如, -date,id将转换为date DESC NULLS LAST, id ASC NULLS LAST 。 它可用于将 HTTP 查询参数转换...

    oracle使用order by排序null值如何处理

    适用情况: oracle 对查询结果进行排序时,被排序的栏位存在null值,且要指定NULL值排在最前面或者最后面 关键字:Nulls First;Nulls Last 默认情况:null 默认为最大值(即:asc 升序&lt;小–&gt;大&gt;,null值排在最后...

    oralce 中 排序问题

    ORDER BY last_name NULLS LAST, first_name ASC; ``` 在这个例子中,如果`last_name`为空,那么这些记录将在非空的`last_name`记录之后显示,而`first_name`则按升序排列。 总之,Oracle中的排序是一个涉及广泛的...

    oracle排序

    SELECT * FROM perexl ORDER BY danwei DESC NULLS LAST; 十一、使用 DECODE 函数对 NULL 值进行处理 在 Oracle 中,可以使用 DECODE 函数对 NULL 值进行处理。例如,以下语句将对 perexl 表中的数据按照 danwei ...

    对Oracle 排序中的几种常用排序的介绍

    8. **分页查询**:Oracle中通常使用`ROWNUM`进行分页,但要注意`ORDER BY`和`ROWNUM`的配合使用。如果先`ORDER BY`再用`ROWNUM`,可能会导致分页结果不正确。正确的做法是: ```sql select * from ( select ...

    oracle处理的类型 oracle行排序

    SELECT * FROM table_name ORDER BY column_name NULLS FIRST/LAST; ``` Oracle还支持多列排序,可以同时按照多个列进行排序,先按第一列排序,再按第二列排序,以此类推。例如: ```sql SELECT * FROM table_name...

    sql 语句大全sql教程

    NULLS FIRST`和`ORDER BY ... NULLS LAST`可以让空值出现在排序的前面或后面。在示例中,`NULLS LAST`确保空值不会打乱其他非空值的顺序,而`NULLS FIRST`则让空值排在最前。 5. **根据数据项的键排序**:`CASE`...

    Oracle开发之分析函数(Top/Bottom N、First/Last、NTile)

    通过在`ORDER BY`子句中使用`NULLS LAST/FIRST`,我们可以指定空值是排在最后还是最前。例如: ```sql SELECT region_id, customer_id, SUM(customer_sales) cust_total, RANK() OVER (PARTITION BY region_id ...

    Struts+Hibernate的一个好用分页实例

    本文介绍了一种基于Struts和Hibernate实现高效分页的方法,特别是在数据库不支持分页查询的情况下。通过自定义存储过程`Ture_Page`以及正确的Hibernate配置,可以显著提高系统性能,优化用户体验。这种方法不仅适用...

    (开发人员应当读的文章)Bob Lyle 谈 DB2 中的 OLAP 函数

    这里使用`PARTITION BY dept`来定义每个部门为一个独立的分区,`ORDER BY salary DESC NULLS LAST`则指定了在每个部门内部按照薪水降序排列,并将空值排在最后。 #### 五、输出结果示例 输出结果展示了每个员工的...

    Oracle_SQL学习笔记

    4. **ORDER BY NULLS LAST**:在排序时,`NULLS LAST`选项确保NULL值在排序结果的最后出现,如`ORDER BY area_code, bill_month NULLS LAST`。 5. **NVL 函数家族**:NVL函数用于处理NULL值。`NVL(a,1)`当a为NULL时...

    Oracle_SQL学习笔记.doc

    4. **ORDER BY 子句中的 NULLS LAST**:在`ORDER BY`子句中,`NULLS LAST`选项确保`NULL`值在排序时出现在最后,例如`ORDER BY area_code, bill_month NULLS LAST`。 5. **NVL 函数家族**: - `NVL(a, b)`:如果`a...

    list_nulls.rar_Over

    在提供的`list_nulls.c`文件中,我们可能找到具体的实现细节,例如如何定义`hlist`结构体,如何初始化链表,以及如何遍历并处理空节点。这可能包括对特定宏的使用,比如Linux内核中的`hlist_for_each_entry`或`hlist...

    oracle 分析函数总结

    Order子句则用于定义行的排序,可以包含ASC或DESC关键字,以及NULLS FIRST或NULLS LAST选项来控制NULL值的位置。Window子句更为复杂,它定义了分析函数的工作范围,可以基于行数(ROWS BETWEEN)或值范围(RANGE ...

    ORACLE OLAP函数语法的总结

    DENSE_RANK() OVER (PARTITION BY deptno ORDER BY sal DESC NULLS LAST) AS dense_rank, ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY sal DESC NULLS LAST) AS row_number FROM emp; ``` - **RANK()**:为...

    nulls_for_goals

    nulls_for_goals

    Oracle数据库中对null值的排序及mull与空字符串的区别

    在实际项目中,例如在类`mod_gcdownload`的`get_gcdownload_datalist`方法中,可能需要根据各种条件(如日期范围、版本、合作ID等)来构造SQL查询,并结合`ORDER BY`语句对结果进行排序。在这种情况下,理解并正确...

    分析函数详解

    - **语法**:`RANK() OVER (PARTITION BY &lt;partition_by_clause&gt; ORDER BY &lt;order_by_clause&gt; NULLS { FIRST | LAST })` - `PARTITION BY`子句用于将数据集分成多个分区,在每个分区内进行排名。 - `ORDER BY`子句...

Global site tag (gtag.js) - Google Analytics