六、抓取策略:抓取策略主要是指獲取鏈接對象的策略。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() {