论坛首页 Java企业应用论坛

一个关于Hibernate的优化实例:从HQL到QBC,从QBC到QBE,再到“增强的”QBE

浏览 43224 次
该帖已经被评为良好帖
作者 正文
   发表时间:2008-09-01  
我最早都是用得QBC,很好用
后来用公司框架后改用HQL了
0 请登录后投票
   发表时间:2008-09-01  
主要是还是公司过分得封装,使得代码的灵活性变差了
0 请登录后投票
   发表时间:2008-09-01  
zrq 写道
Hibernate 的Cirteria 本意是好的,但在实际项目中,最好别用它,因为实际项目中的查询大部分是复杂查询。我给大家介绍一个我认为最好的方法,iBatis 还是太难用了。

1 要用HQL或者 native SQL;
2.要解决参数的占位符问题;
3.要解决动态HQL或SQL问题;
4.要解决数据库表到对象的映射问题。

第二条方案  用named parameter,need to prprocess the sql statement.
第三条方案,用Velocity 或者FreeMarker 模板解决。
第四条方案,用JAVA Reflection 自动映射。

例子:

SELECT FIRST_NAME firstName
      ,LAST_NAME lastName
from users u
where 1=1

#if($firstName)
and u.first_name like #{firstName}
#end

#if($lastName)
and u.last_name like #{lastName}
#end




Java code:

Map map=new HashMap();

map.put("firstName",u.firstName);
map.put("lastName", u.lastName);

List<UserVO> userList=dao.findList(map, "yourSQLName",UserVO.class);






用模板还是等于封装了一层,换汤不换药,而且得不到IDE良好的支持,编译期检查也没有。感觉这个复杂度用动态语言或者未来的Java7降低,效果能更好一点,我指代码的开发、调试和修改效率。其实在Java里用几个if没啥不好,很多情况,每个if中处理都是不太一样的,一定要刻意的提炼成一套东西(相当于再封装一层)实在没有太大必要。
1 请登录后投票
   发表时间:2008-09-01  
ray_linn 写道
movingboy 写道
ray_linn 写道
浪费这么多行代码,做的都是无用功。

能否请你说明一下为何你认为这么做是浪费,是做无用功?对于文中提到的问题,你会怎么解决呢?


连基本的查询方式in range, (26<会员.age<35)都没办法做到,是不是毫无价值?

要解决这个问题很简单,我写个HSQLTemplate

<dynamic-query name="memberList">
from Member m where [#Mix<m.age<#Max] and (m.salary>#salary) and [m.city in (@city)] and m.gender=#gender
</dynamic-query>

# 代表变量, @代表集合,[] 代表若变量为null,则该条件被忽略。俺只需要把HSQLTemplate注入DAO中,接受一个Map作为参数就可以完成HSQL的自动拼装。

这样的HSQL生成器不难吧?

这样的查询不过分吧?包括了in range和in list 你的QBE根本就做不到,就是做到了也是麻烦得不得了。


受教了,多谢指点。
0 请登录后投票
   发表时间:2008-09-02  
Quake Wang 写道
根据用户输入,动态创建查询是很常见的需求,但是Query By Example只能解决简单的属性对比,正如同你说的,between查询或者一个in查询都是很麻烦的。

Query By Criterion是解决这种需求的最好方法,你需要实现的只是一个将用户输入转化成动态创建Criterion的通用方法,能够将map或者list之类容器中的值转化即可:
["eq", "propertyName", "abc"], ["between", "propertyName", "lo", "hi"], ["in", "propertyName", [1, 2, 3]] => Restrictions.eq and Restrictions.between and Restrictions.in

Restrictions只是对各种Criterion实现的提供了静态方法调用,你也可以直接实现一个map/list => criterion的转化方法。

/**
	 * 根据Map获得多个SizeExpression
	 */
	public static List<SizeExpression> map(Map<String, Object> map, String op) {
		List<SizeExpression> list = new ArrayList<SimpleExpression>();
		for (String key : map.keySet()) {
			list.add(new SizeExpression(key, map.get(key), op));
		}
		return list;
	}
0 请登录后投票
   发表时间:2008-09-02  
ice123456 写道
Quake Wang 写道
根据用户输入,动态创建查询是很常见的需求,但是Query By Example只能解决简单的属性对比,正如同你说的,between查询或者一个in查询都是很麻烦的。

Query By Criterion是解决这种需求的最好方法,你需要实现的只是一个将用户输入转化成动态创建Criterion的通用方法,能够将map或者list之类容器中的值转化即可:
["eq", "propertyName", "abc"], ["between", "propertyName", "lo", "hi"], ["in", "propertyName", [1, 2, 3]] => Restrictions.eq and Restrictions.between and Restrictions.in

Restrictions只是对各种Criterion实现的提供了静态方法调用,你也可以直接实现一个map/list => criterion的转化方法。

/**
	 * 根据Map获得多个SizeExpression
	 */
	public static List<SizeExpression> map(Map<String, Object> map, String op) {
		List<SizeExpression> list = new ArrayList<SimpleExpression>();
		for (String key : map.keySet()) {
			list.add(new SizeExpression(key, map.get(key), op));
		}
		return list;
	}

你这段代码是打算实现“一个map/list => criterion的转化方法”吗?我有三个疑问:

1.按照Quake Wang的建议,这个map或list中的每一项都包含一个操作符、一个属性名称及一或多个操作数,但你的代码中针对该map中所有项都使用了同一个操作符

2.你的代码中有一行

List<SizeExpression> list = new ArrayList<SimpleExpression>();


SizeExpression和SimpleExpression是不同的类型,ArrayList<SimpleExpression>可以转型为List<SizeExpression>吗?个人猜测代码中的SizeExpression应该都换成SimpleExpression,不知道对不对?

3.按照你的思路,似乎还是无法解决between和in操作的问题(我看了SimpleExpression的源码,看不出来它支持这两种操作)
0 请登录后投票
   发表时间:2008-09-03  
ray_linn 写道
movingboy 写道
ray_linn 写道
浪费这么多行代码,做的都是无用功。

能否请你说明一下为何你认为这么做是浪费,是做无用功?对于文中提到的问题,你会怎么解决呢?


连基本的查询方式in range, (26<会员.age<35)都没办法做到,是不是毫无价值?

要解决这个问题很简单,我写个HSQLTemplate

<dynamic-query name="memberList">
from Member m where [#Mix<m.age<#Max] and (m.salary>#salary) and [m.city in (@city)] and m.gender=#gender
</dynamic-query>

# 代表变量, @代表集合,[] 代表若变量为null,则该条件被忽略。俺只需要把HSQLTemplate注入DAO中,接受一个Map作为参数就可以完成HSQL的自动拼装。

这样的HSQL生成器不难吧?

这样的查询不过分吧?包括了in range和in list 你的QBE根本就做不到,就是做到了也是麻烦得不得了。



很早就尝试过将ibates中拼接SQL的代码提取出来,集成到hibernate中做HQL的拼接.貌似ray_linn这个做法也是从ibates中获得的灵感吧.有点古老了,不必以此打击楼主.
0 请登录后投票
   发表时间:2008-09-03  
wym0291 写道

很早就尝试过将ibates中拼接SQL的代码提取出来,集成到hibernate中做HQL的拼接.貌似ray_linn这个做法也是从ibates中获得的灵感吧.有点古老了,不必以此打击楼主.



我打击的他的方案,而不是打击他本人。方案得经得住别人的chanllenge。
若是连这点chanllenge都经不住,就不用来论坛发贴了。

ps: 我只返回一个namedparam给hibernate,设参数的工作还是让hibernate自己去完成。
0 请登录后投票
   发表时间:2008-09-03  
qbc是不是不能实现having子句?
我以前问过 一直没人回答
1 请登录后投票
   发表时间:2008-09-03  
laiseeme 写道
qbc是不是不能实现having子句?
我以前问过 一直没人回答


不能,100%肯定。请用HQL。

3.2.6之后的版本我不知道。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics