六、抓取策略:抓取策略主要是指获取链接对象的策略。java
6.一、基于XML的抓取sql
1.一、基于XML抓取many-to-onesession
session = HibernateUtil.openSession(); /** * 默认状况会发出3条SQL语句,一条取Student,一条取Classroom,一条取Special * many-to-one的默认状况,使用的是延迟加载 */ Student stu = session.load(Student.class, 1); System.out.println(stu.getName()+","+stu.getClassroom().getName()+","+stu.getClassroom().getSpecial().getName());
1.二、设置fetch="join"app
session = HibernateUtil.openSession(); /** * 默认状况会发出3条SQL语句,一条取Student,一条取Classroom,一条取Special * 经过设置XML中的<many-to-one name="classroom" column="cid" fetch="join"/> * 能够完成对抓取的设置,只会发出一条SQL语句 */ Student stu = session.load(Student.class, 1); System.out.println(stu.getName()+","+stu.getClassroom().getName()+","+stu.getClassroom().getSpecial().getName());
<!-- 设置了fetch="join"以后,会链接查询将对象加载出来 --> <many-to-one name="classroom" column="cid" fetch="join"/>
存在问题:延迟加载失效fetch
session = HibernateUtil.openSession(); /** * 使用fetch="join"虽然能够将关联对象抓取,可是若是不使用关联对象也会一并查询出来 * 这样会占用相应的内存 */ Student stu = session.load(Student.class, 1); //延迟加载就失效 System.out.println(stu.getName());
1.三、可是fetch="join"没法抓取HQL中的list,若是须要抓取HQL中的list有两种方法:this
·设置one这一端对象的batch-size,此时会经过in的语句来加载多条数据。hibernate
<hibernate-mapping package="org.pm.hibernate.model"> <!-- 设置batch-size="20",在抓取Classroom的时候,会一下抓取20Classroom的记录 --> <class name="Classroom" table="t_classroom" batch-size="20"> <id name="id"> <generator class="native"/> </id>
session = HibernateUtil.openSession(); /** * 在XML中配置了fetch="join"仅仅只是对load的对象有用,对HQL中查询的对象无用, * 因此此时会发出查询班级的SQL,解决这个SQL的问题有两种方案, * 一种是设置对象的抓取的batch-size * 另外一种方案在HQL中指定抓取 */ List<Student> stus = session.createQuery("from Student", Student.class).getResultList(); for(Student stu:stus) { System.out.println(stu.getName()+","+stu.getClassroom().getName()); }
·在HQL语句中写预抓取(特别注意:使用预抓取不支持count(*)查询)ssr
session = HibernateUtil.openSession(); /** * 在XML中配置了fetch="join"仅仅只是对load的对象有用,对HQL中查询的对象无用, * 因此此时会发出查询班级的SQL,解决这个SQL的问题有两种方案, * 一种是设置对象的抓取的batch-size * 另外一种方案在HQL中指定抓取,经过在HQL中添加fetch关键字完成抓取 * 特别注意:若是使用了join fetch就没法使用count(*) */ List<Student> stus = session.createQuery("select stu from " + "Student stu join fetch stu.classroom", Student.class).getResultList(); for(Student stu:stus) { System.out.println(stu.getName()+","+stu.getClassroom().getName()); }
1.四、集合抓取code
<!-- 设置fetch="subselect",对于list查询它会根据查询的结果来完成对对象的子查询 --> <set name="stus" inverse="true" lazy="extra" fetch="subselect"> <key column="cid"/> <one-to-many class="Student"/> </set>
session = HibernateUtil.openSession(); List<Classroom> clas = session.createQuery("from Classroom", Classroom.class).getResultList(); for(Classroom cla:clas) { System.out.println(cla.getName()); /* * 抓取集合,默认是select,此时会为每个班的学生发出sql * 对于经过HQL取班级列表而且获取相应的学生列表时,fetch="join"就无效了 * 第一种方案能够设置set的batch-size来完成批量的抓取 * 第二种方案能够设置fetch=subselect,使用subselect会完成根据查询出来的班级 * 进行一次对学生对象的子查询 */ for(Student stu:cla.getStus()) { System.out.print(stu.getName()); } }
对于集合抓取而言,有三种设置方式:select(默认),join,subselect。xml
其中在查询单个对象时,select和subselect彻底同样,都是在须要查询集合对象时才发出sql,可是join会
使用链接查询。
在查询列表对象时,select和join同样(能够经过设置set的batch-size设置抓取的数量)
最佳实践:不少状况不会设置one-to-many,若是要设置one-to-many能够设置为subselect。
6.二、基于Annotation的抓取
一、基于Annotation的many-to-one
session = HibernateUtil.openSession(); /** * 对于Annotation的配置而言,默认就是基于join的抓取的,因此只会发出1条SQL */ Student stu = session.load(Student.class, 1); System.out.println(stu.getName()+","+stu.getClassroom().getName()+","+stu.getClassroom().getSpecial().getName());
session = HibernateUtil.openSession(); /** * 基于Annotation的配置没有延迟加载,此时会把全部的关联对象查询出来,发出大量的SQL语句 */ List<Student> stus = session.createQuery("from Student", Student.class).getResultList(); for(Student stu:stus) { System.out.println(stu.getName()+","+stu.getClassroom().getName()); }
@ManyToOne(fetch=FetchType.EAGER) //LAZY就是XML中select,EAGER就表示XML中的join @JoinColumn(name="cid") public Classroom getClassroom() { return classroom; } public void setClassroom(Classroom classroom) { this.classroom = classroom; }
session = HibernateUtil.openSession(); /** * 基于Annotation,因为many-to-one的默认抓取策略是EAGER的,因此当抓取Classroom * 时会自动发出多条SQL去查询相应的Special,此时能够经过join fetch继续完成对关联的 * 抓取,或者直接将关联对象的fetch设置为LAZY,可是使用LAZY所带来的问题是在查询 * 关联对象时须要发出相应的SQL,不少时候也会影响效率 */ List<Student> stus = session.createQuery("select stu from " + "Student stu join fetch stu.classroom cla join fetch cla.special", Student.class).getResultList(); for(Student stu:stus) { System.out.println(stu.getName()+","+stu.getClassroom().getName()); }
可使用@BatchSize
@Entity @Table(name="t_classroom") @BatchSize(size=20) public class Classroom { private int id; private String name; private int grade; private Set<Student> stus; private Special special;
二、集合抓取
@OneToMany(mappedBy="classroom") @LazyCollection(LazyCollectionOption.EXTRA) @Fetch(FetchMode.SUBSELECT) //在Annotation中须要经过这种方式才能设置subselect public Set<Student> getStus() { return stus; } public void setStus(Set<Student> stus) { this.stus = stus; } @ManyToOne(fetch=FetchType.LAZY) @JoinColumn(name="spe_id") public Special getSpecial() {