hibernate 连接查询方式之案例分析
Hibernate效率分析:
连接查询:
说明:在使用hibernate的时候,如果是一个双向的一对多的关联映射,如:(环境)
publicclassStudent{
privateintid;
privateStringname;
privateTheClassincludeClass;
}
publicclassTheClass{
privateintid;
privateStringname;
privateSet<Student>stuList;
}
在数据库中的表student中有一个字段theclassid(但是并没有建立数据库外键关联)
下面是hibernate映射文件:
<classname="TheClass"table="class">
<idname="id"column="classid"></id>
<propertyname="name"></property>
<setname="stuList"cascade="all"inverse="true">
<keycolumn="theclassid"/>
<one-to-manyclass="Student"/>
</set>
</class>
<classname="Student"table="student">
<idname="id"column="studentid">
</id>
<propertyname="name"></property>
<many-to-onename="includeClass"column="theclassid"fetch="join"lazy="false"/>
</class>
这是双向的。单向也是一样。这里面使用的是set而非list。(建议使用set而非list)
1.使用原生sql进行查询
使用原生Sql可以直接通过一条sql语句将全部的字段查询出来,然后自己根据需要进行组装。查询速度会较快,只是组装会比较费时。
2.使用hql进行查询
Hql查询:在我们一对多关联映射的时候如果想查询一的那一方。如果我们希望将与其关联的child都查出来的话。我们可以在配置set的地方添加一个lazy=”false”,这样的话在查询的时候会自动的将其child查询出来。只不过他查询的方式是,先发出一条sql语句将全部的一的那一方的记录查出来。然后遍历该list。根据关联的字段再发一条sql语句将与该一条记录关联的子记录都查询出来。这样就需要共发出1+n条sql语句。解决它的方式中有一种就是使用连接查询。
连接查询即使用join(还有fetch)来进行查询。
例如我们想把class查出来并且想把所有与他关联的student查询出来,一共有几种方法:
1.普通的左外连接:
SessionFactorysessionFactory=HibernateUtil.getSessionFactory();
Sessionsession=sessionFactory.openSession();
session.beginTransaction();
Queryquery=session.createQuery("fromTheClasstleftjoint.stuList");
Listlist=query.list();
System.out.println(list.size());
for(Iteratorit=list.iterator();it.hasNext();)
{
Object[]arr=(Object[])it.next();
System.out.println(arr.length);
for(inti=0;i<arr.length;i++)
{
if(arr[i]==null)
{
System.out.println(i+"--isnull");
continue;
}
System.out.println(arr[i].getClass().getName());
if(i==0)
{
TheClasstempClass=(TheClass)arr[i];
System.out.println(((TheClass)arr[i]).getName());
SettheSet=tempClass.getStuList();
if(theSet!=null&&theSet.size()>0)
{
Iteratorit2=theSet.iterator();
while(it2.hasNext())
{
StudenttempStu=(Student)it2.next();
System.out.println(tempStu.getName());
}
}
}
else
{
System.out.println(((Student)arr[i]).getName());
}
}
}
session.getTransaction().commit();
session.close();
这里使用这种查询方式的时候得到的list里面的每一项是一个Object的数组。其中arr[0]是TheClass对象。Arr[1]是与改TheClass的关联的Student对象。如果与一个TheClass关联的Student一共有五个。那么这个list中会有5个该TheClass对象。他们的arr【1】是与之关联的五个Student。如果一个student也没有。那么会只有一个THeClass对象。且他的arr[1]是null。我们可以自己手动解析该list。然后可以得到我们想要的数据结构。而如果我们通过我们拿到的TheClass对象来获取其中的theStuSet的时候。他里面在此刻并没有值,而当我们一去获取并访问他的时候他也会根据当前的theClass对象发出一条sql语句来查询与之关联的student对象并且组装到这个成员变量中去。
但是这种情况会有所改变:如果我们查询多的一方,然后使用这种方式的话,他会帮助我们把与之相关联的TheClass对象放到Student里面的includeClass成员变量。这时我们可以通过这个直接访问。虽然如此,但是查询得到的list也是object[]。他的结果和上面是一样的。
2.使用添加fetch的join查询:
Queryquery=session.createQuery("fromTheClasstleftjoinfetcht.stuListasc");
Listlist=query.list();
System.out.println(list.size());
for(Iteratorit=list.iterator();it.hasNext();)
{
TheClasstheClass=(TheClass)it.next();
System.out.println(theClass.getName());
Set<Student>stuSet=theClass.getStuList();
if(stuSet!=null&&stuSet.size()>0)
{
Iteratorit2=stuSet.iterator();
while(it2.hasNext())
{
Studentstu=(Student)it2.next();
System.out.println(stu.getName());
}
}else
{
System.out.println("isnull");
}
}
fromTheClasstleftjoinfetcht.stuListasc。这里我们在leftjoin后面添加了一个fetch。这样的话查询得到的list就和上面的不一样了。而是一个TheClass对象的List。所以我们可以直接遍历他,然后访问其中的theStuSet。这就是因为hibernate容器帮我们将join查询出来的数据组装到TheClass的成员变量中去了。