hibernate查询之HQL(2)

我们上次一起学习HQL,知道了怎么使用HQL,现在我们继续来学习一下HQL的其他方面,如通过配置文件来进行配置。

有些项目组有一些奇怪的规定,不许在代码中出现SQL语句,如果这是一个规范,那我见过的我们公司的代码,全部都是不合格的,杯具的一大堆字符串拼接,看着就郁闷啊。维护现有项目的人真是伤不起啊。

代码中不允许出现SQL语句,这是建议是不错,但还是要看场合。我们来看一下Hibernate怎么把HQL配置在映射文件中。

直接看配置文件:

<query name="queryByName">
	<![CDATA[
		from User usr where usr.name=:name
	]]>
</query>

  我们添加了一个这样的标签,它表明里面是HQL语句。

当我们需要取到这个语句时,也只需要在代码中加入一句:

Query query = session.getNamedQuery("queryByName");

  这样也就取到了这个HQL语句。

HQL也可以用SQL中的组合查询,比如inner join,left outer join,right outer join,full join。

下面我们来看一下它们的用法:

还是先看一下实体类,我们测试中要用到的:

public class TUser implements Serializable{

	private static final long serialVersionUID = 1L;

	private int id;
	private int age;
	private String name;
	private Set<Address> addresses = new HashSet<Address>();
        //省略Get/Set方法
}
public class Address implements Serializable{

	private static final long serialVersionUID = 1L;

	private int id;
	private String address;
	private TUser user;
        //省略Get/Set方法
}

  下面我们看一下映射文件:

<hibernate-mapping package="org.hibernate.tutorial.domain6">
	<class name="TUser" table="t_user" dynamic-insert="true" dynamic-update="true">
		<id name="id" column="id">
			<generator class="native" />
		</id>
		<property name="name" type="java.lang.String" column="name"/>
		<property name="age" type="java.lang.Integer" column="age"/>
		<set name="addresses" cascade="all" table="t_address" inverse="true">
			<key column="user_id" />
			<one-to-many class="Address"/>
		</set>
	</class>
</hibernate-mapping>
<hibernate-mapping package="org.hibernate.tutorial.domain6">
	<class name="Address" table="t_address" dynamic-insert="false" dynamic-update="false">
		<id name="id" column="id" type="java.lang.Integer">
			<generator class="native" />
		</id>
		<property name="address" column="address" type="java.lang.String" />
		<many-to-one name="user" class="TUser" 
			column="user_id" not-null="true"></many-to-one>
	</class>
</hibernate-mapping>

  大家只要做一下相应的包名修改就可以了。

下面我们正式进行测试:

在测试前我们看一下表中的数据:

t_address表数据如下:

t_user表数据如下:

1)首先我们看一下inner join,它在HQL中由inner join fetch,注意这里fetch的意思是指把需要的数据取出来,如果不用fetch,我们取出来的数据是Object[]数据类型的。

我们先看一下

from TUser usr inner join fetch usr.addresses

  当我们运行它时,我们看到hibernate输出为:

Hibernate: select tuser0_.id as id1_0_, addresses1_.id as id0_1_, tuser0_.name as name1_0_, tuser0_.age as age1_0_, addresses1_.address as address0_1_, addresses1_.user_id as user3_0_1_, addresses1_.user_id as user3_0__, addresses1_.id as id0__ from t_user tuser0_ inner join t_address addresses1_ on tuser0_.id=addresses1_.user_id

  我们在mysql中运行可以看到结果:

 

我们可以看到hibernate将它转换成inner join语句,并查出address。

我们看到结果中并没有shun4这个记录,因为他并没有相应的address与它记录。

而我们用inner join而不要fetch时,它打印的语句为:

Hibernate: select tuser0_.id as id1_0_, addresses1_.id as id0_1_, tuser0_.name as name1_0_, tuser0_.age as age1_0_, addresses1_.address as address0_1_, addresses1_.user_id as user3_0_1_ from t_user tuser0_ inner join t_address addresses1_ on tuser0_.id=addresses1_.user_id

  似乎语句没什么区别,但是当我们查出来后它得到的是Object[]数组类型的,这个解析的时候需注意。

当我们不用fetch,而只是inner join时,我们需要这样来解析:

Query query = session.createQuery("from TUser usr inner join usr.addresses");

List list = query.list();
Iterator iter = list.iterator();
		
while(iter.hasNext()) {
       Object[] results = (Object[])iter.next();
       for (int i = 0; i < results.length; i ++ ) {
	    System.out.println(results[i]);
       }
}

  我们看到打印的结果:

org.hibernate.tutorial.domain6.TUser@16925b0
org.hibernate.tutorial.domain6.Address@914f6a
org.hibernate.tutorial.domain6.TUser@787d6a
org.hibernate.tutorial.domain6.Address@71dc3d
org.hibernate.tutorial.domain6.TUser@1326484
org.hibernate.tutorial.domain6.Address@16546ef

  它的每个结果都是相应查出来的对象。

2)left outer join,这个相当于SQL的左连接,我们直接看一下例子:

from TUser usr left outer join fetch usr.addresses

  当我们运行上面的语句时,hibernate打印出:

Hibernate: select tuser0_.id as id1_0_, addresses1_.id as id0_1_, tuser0_.name as name1_0_, tuser0_.age as age1_0_, addresses1_.address as address0_1_, addresses1_.user_id as user3_0_1_, addresses1_.user_id as user3_0__, addresses1_.id as id0__ from t_user tuser0_ left outer join t_address addresses1_ on tuser0_.id=addresses1_.user_id

  我们在mysql中进行查出,看到:

  我们看到,尽管shun4没有对应的adress,但还是把它查出来,left outer join是指把左边表的记录全部查出。

没有fetch的情况这里就不讲了。

3)接下来我们看一下right outer join,看名字肯定就和left outer join有点关系的,我们直接看例子就可以明显看出了。

from TUser usr right outer join fetch usr.addresses

  我们执行它,得到Hibernate输出的结果语句为:

Hibernate: select tuser0_.id as id1_0_, addresses1_.id as id0_1_, tuser0_.name as name1_0_, tuser0_.age as age1_0_, addresses1_.address as address0_1_, addresses1_.user_id as user3_0_1_, addresses1_.user_id as user3_0__, addresses1_.id as id0__ from t_user tuser0_ right outer join t_address addresses1_ on tuser0_.id=addresses1_.user_id

  我们在mysql中执行后可以看到结果:

  这里我们可以看到address为Test4的并没有相应的user与它对应,但它还是并查出来了,right outer join是指把右边表的记录全部查出。

fetch的情况如上,如果不明白可以看一下inner join fetch。

4)接下来我们看最后一个full join,这个用得比较少,我们就大概看一下:

实际上前面两个理解了,这个就不难理解了,只是把前面两个的结果结合一下而已。

我们直接看例子:

from TUser usr full join fetch usr.addresses

  我们执行它,很抱歉,不管怎样执行,我们都会得到一个错误:

org.hibernate.AssertionFailure: undefined join type 23

  这个错误暂时没找到解决方法,可能是hibernate的bug,等以后我们深入源代码时再重回来看看。

HQL当然也是可以用子查询和多表联合查询的啦,这个就不多讲了。

HQL我们就学习到这里啦,以后会有更多高级的,我们再继续研究。

猜你喜欢

转载自cxshun.iteye.com/blog/1063009
今日推荐