统计每一个专业的人数:
void test17() {
Session s=null;
try {
s=HibernateUtil.getSession();
List<Object[]> objs=s.createQuery("select spe.name,count(stu.classroom.special.id) from Student stu right join stu.classroom.special spe group by spe.id").list();
for(Object[] obj:objs) {
System.out.println(obj[0]+":"+obj[1]);
}
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
s.getTransaction().rollback();
}finally {
HibernateUtil.closeSession(s);
}
}
统计人数大于200的专业(用having):
void test18() {
Session s=null;
try {
s=HibernateUtil.getSession();
List<Object[]> objs=s.createQuery("select spe.name,count(stu.classroom.special.id) from Student stu right join stu.classroom.special spe group by spe.id having count(stu.classroom.special.id)>200").list();
for(Object[] obj:objs) {
System.out.println(obj[0]+":"+obj[1]);
}
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
s.getTransaction().rollback();
}finally {
HibernateUtil.closeSession(s);
}
}
统计每一个专业男生女生人数:
void test19() {
Session s=null;
try {
s=HibernateUtil.getSession();
List<Object[]> objs=s.createQuery("select spe.name,stu.sex,count(stu.classroom.special.id) from Student stu right join stu.classroom.special spe group by spe.id,stu.sex").list();
for(Object[] obj:objs) {
System.out.println(obj[0]+":"+obj[1]+":"+obj[2]);
}
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
s.getTransaction().rollback();
}finally {
HibernateUtil.closeSession(s);
}
}
基于XML:
void test20() {
Session s=null;
try {
s=HibernateUtil.getSession();
Student stu=s.load(Student.class, 1);
System.out.println(stu.getName()+","+stu.getClassroom().getName()+","+stu.getClassroom().getSpecial().getName());
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
s.getTransaction().rollback();
}finally {
HibernateUtil.closeSession(s);
}
}
执行该代码需要3条sql语句,因为延迟加载,如何解决?可以在Student.hbm.xml和Classroom.hbm.xml中的many-to-one中加入fetch="join",则完成join连接,一条sql语句搞定
缺点:当不需要classroom和special的数据时,也会自动完成连接,占用内存,降低效率,所以join看情况使用
基于annotation:annotation自动完成join操作,所以只需要一条语句,但是from student,没有获取classroom,也自动完成join操作,发2条语句
void test21() {
Session s=null;
try {
s=HibernateUtil.getSession();
List<Student> stus=s.createQuery("from Student").list();
for(Student stu:stus) {
System.out.println(stu.getName()+","+stu.getClassroom());
}
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
s.getTransaction().rollback();
}finally {
HibernateUtil.closeSession(s);
}
}
如何解决?获取student不需要获取classroom,把student的@ManyToOne修改为@ManyToOne(fetch=FetchType.LAZY),即延迟加载,不需要就不会获取了,所以就只发一条sql语句
void test21() {
Session s=null;
try {
s=HibernateUtil.getSession();
List<Student> stus=s.createQuery("from Student").list();
for(Student stu:stus) {
System.out.println(stu.getName()+","+stu.getClassroom());
}
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
s.getTransaction().rollback();
}finally {
HibernateUtil.closeSession(s);
}
}
XML设置fetch=“join”对HQL语句不起作用,所以stu.getClassroom()并不会完成连接,而是先发查所有student的sql,查所有学生分别有哪些班级id,再发根据班级id查班级的sql
这个情况会发大量sql,如何解决?
(1).Classroom.java的@Entity下面加上@BatchSize(size=20),一次抓20个班级,不过这个方式不灵活
<hibernate-mapping>
<class name="model.Classroom" table="CLASSROOM" batch-size="20">
<id name="id" type="int">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="grade" type="int">
<column name="GRADE" />
</property>
<set name="stus" inverse="true" lazy="extra" fetch="join">
<key>
<column name="c_id" />
</key>
<one-to-many class="model.Student" />
</set>
<many-to-one name="special" fetch="join" >
<column name="spe_id" />
</many-to-one>
</class>
</hibernate-mapping>
注意: <class name="model.Classroom" table="CLASSROOM" batch-size="20">,batch-size="20"是在<class>里面的
(2).使用join fetch
void test22() {
Session s=null;
try {
s=HibernateUtil.getSession();
List<Student> stus=s.createQuery("select stu from Student stu join fetch stu.classroom cla").list();
for(Student stu:stus) {
System.out.println(stu.getName()+","+stu.getClassroom());
}
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
s.getTransaction().rollback();
}finally {
HibernateUtil.closeSession(s);
}
}
因为在XML中fetch=“join”语句对HQL不起作用,所以当使用join fetch可以把fetch=“join”删除,同时记得把BatchSize(size=20)删除,使用join fetch语句,只发一条sql就取到student和classroom的Name了
注意:使用joinFetch,就不能使用count
joinfetch(基于annotation):
annotation自动完成join,不过我们不需要取special,就把classroom中的manytoone加个lazy,不过对于HQL语句,from student还是先取student再取每一个班级,如何解决?用join fetch
在XML中针对1的抓取(单向关联):
void test23() {
Session s=null;
try {
s=HibernateUtil.getSession();
Classroom cla=s.load(Classroom.class, 1);
for(Student stu:cla.getStus()) {
System.out.println(stu.getName());
}
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
s.getTransaction().rollback();
}finally {
HibernateUtil.closeSession(s);
}
}
此时会发条sql,一条取此班级,一条根据此班级的id取该班级的学生,如果在set中加入fetch=“join”,则一条
在XML中子查询:
void test26() {
Session s=null;
try {
s=HibernateUtil.getSession();
List<Classroom> clas=s.createQuery("from Classroom").list();
for(Classroom cla:clas) {
for(Student stu:cla.getStus()) {
System.out.println(stu.getName());
}
}
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
s.getTransaction().rollback();
}finally {
HibernateUtil.closeSession(s);
}
}
如果不使用子查询,会发大量sql,由于该代码是根据cla取stu,所以在cla的hbm中的set加入fetch="subselect",就实现子查询,条sql搞定
在annotation中子查询:
在getStus上面加入@Fetch(FetchMode.SUBSELECT)即可实现