hibernate 连接查询方式之案例分析

Hibernate 效率分析:
连接查询:
   说明:在使用hibernate的时候,如果是一个双向的一对多的关联映射,如:(环境)
public class Student {
private int id;
private String name;
private TheClass includeClass;
}

public class TheClass {
private int id;
private String name;
private Set<Student> stuList;
}

在 数据库中的表student中有一个字段theclassid(但是并没有建立数据库外键关联)
下面是hibernate映射文件:
   <class name="TheClass" table="class">
   <id name="id" column="classid"></id>
   <property name="name"></property>
  
   <set name="stuList"  cascade="all" inverse="true">
       <key column="theclassid"/>
       <one-to-many class="Student"/>
   </set>

   </class>

   <class name="Student" table="student">
     <id name="id" column="studentid">
     
     </id>
     <property name="name"></property>
     <many-to-one name="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. 普通的左外连接:
  SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();

Query query = session.createQuery("from TheClass  t left join t.stuList");
List list = query.list();
System.out.println(list.size());
for(Iterator it = list.iterator();it.hasNext();)
{
  Object[] arr = (Object[])it.next();
System.out.println(arr.length);
for(int i=0;i<arr.length;i++)
{
if(arr[i]==null)
{
System.out.println(i+"--is null");
continue;
}
System.out.println(arr[i].getClass().getName());
      
if(i==0)
{
TheClass tempClass = (TheClass)arr[i];
        System.out.println(((TheClass)arr[i]).getName());
Set theSet = tempClass.getStuList();
if(theSet!=null&&theSet.size()>0)
{
Iterator it2 = theSet.iterator();
while(it2.hasNext())
{
Student tempStu = (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查询:
Query query = session.createQuery("from TheClass  t left join fetch t.stuList as c");
 
   
   
    List list = query.list();

    System.out.println(list.size());
    for(Iterator it = list.iterator();it.hasNext();)
    {
             TheClass theClass = (TheClass)it.next();
             System.out.println(theClass.getName());
             Set<Student> stuSet = theClass.getStuList();
             if(stuSet!=null&&stuSet.size()>0)
             {
            Iterator it2 = stuSet.iterator();
            while(it2.hasNext())
            {
            Student stu = (Student)it2.next();
            System.out.println(stu.getName());
            }
             }else
             {
            System.out.println(" i s null");
             }
   
}


from TheClass  t left join fetch t.stuList as c。这里我们在left join后面添加了一个fetch。这样的话查询得到的list就和上面的不一样了。而是一个TheClass对象的List。所以我们可以直接遍历他,然后访问其中的theStuSet。这就是因为hibernate容器帮我们将join查询出来的数据组装到TheClass的成员变量中去了。

猜你喜欢

转载自buzuibuxiu.iteye.com/blog/1028059