Hibernate抓取策略
為什么80%的碼農(nóng)都做不了架構(gòu)師?>>> ??
6、抓取策略:抓取策略主要是指獲取連接對象的策略。
? ? 6.1、基于XML的抓取
? ? 1.1、基于XML抓取many-to-one
session = HibernateUtil.openSession();/*** 默認(rèn)情況會發(fā)出3條SQL語句,一條取Student,一條取Classroom,一條取Special* many-to-one的默認(rèn)情況,使用的是延遲加載*/Student stu = session.load(Student.class, 1);System.out.println(stu.getName()+","+stu.getClassroom().getName()+","+stu.getClassroom().getSpecial().getName());? ? 1.2、設(shè)置fetch="join"
session = HibernateUtil.openSession();/*** 默認(rèn)情況會發(fā)出3條SQL語句,一條取Student,一條取Classroom,一條取Special* 通過設(shè)置XML中的<many-to-one name="classroom" column="cid" fetch="join"/>* 可以完成對抓取的設(shè)置,只會發(fā)出一條SQL語句*/Student stu = session.load(Student.class, 1);System.out.println(stu.getName()+","+stu.getClassroom().getName()+","+stu.getClassroom().getSpecial().getName()); <!-- 設(shè)置了fetch="join"之后,會連接查詢將對象加載出來 --><many-to-one name="classroom" column="cid" fetch="join"/>? ? 存在問題:延遲加載失效
session = HibernateUtil.openSession();/*** 使用fetch="join"雖然可以將關(guān)聯(lián)對象抓取,但是如果不使用關(guān)聯(lián)對象也會一并查詢出來* 這樣會占用相應(yīng)的內(nèi)存*/Student stu = session.load(Student.class, 1);//延遲加載就失效System.out.println(stu.getName());????1.3、但是fetch="join"無法抓取HQL中的list,如果需要抓取HQL中的list有兩種方法:
????? ? ·設(shè)置one這一端對象的batch-size,此時(shí)會通過in的語句來加載多條數(shù)據(jù)。
<hibernate-mapping package="org.pm.hibernate.model"><!-- 設(shè)置batch-size="20",在抓取Classroom的時(shí)候,會一下抓取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中查詢的對象無用,* 所以此時(shí)會發(fā)出查詢班級的SQL,解決這個(gè)SQL的問題有兩種方案,* 一種是設(shè)置對象的抓取的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語句中寫預(yù)抓取(特別注意:使用預(yù)抓取不支持count(*)查詢)
session = HibernateUtil.openSession();/*** 在XML中配置了fetch="join"僅僅只是對load的對象有用,對HQL中查詢的對象無用,* 所以此時(shí)會發(fā)出查詢班級的SQL,解決這個(gè)SQL的問題有兩種方案,* 一種是設(shè)置對象的抓取的batch-size* 另一種方案在HQL中指定抓取,通過在HQL中添加fetch關(guān)鍵字完成抓取* 特別注意:如果使用了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.4、集合抓取
<!-- 設(shè)置fetch="subselect",對于list查詢它會根據(jù)查詢的結(jié)果來完成對對象的子查詢 --><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());/** 抓取集合,默認(rèn)是select,此時(shí)會為每一個(gè)班的學(xué)生發(fā)出sql* 對于通過HQL取班級列表并且獲取相應(yīng)的學(xué)生列表時(shí),fetch="join"就無效了* 第一種方案可以設(shè)置set的batch-size來完成批量的抓取* 第二種方案可以設(shè)置fetch=subselect,使用subselect會完成根據(jù)查詢出來的班級* 進(jìn)行一次對學(xué)生對象的子查詢*/for(Student stu:cla.getStus()) {System.out.print(stu.getName());}}? ? 對于集合抓取而言,有三種設(shè)置方式:select(默認(rèn)),join,subselect。
? ? 其中在查詢單個(gè)對象時(shí),select和subselect完全一樣,都是在需要查詢集合對象時(shí)才發(fā)出sql,但是join會
????使用連接查詢。
? ? 在查詢列表對象時(shí),select和join一樣(可以通過設(shè)置set的batch-size設(shè)置抓取的數(shù)量)
最佳實(shí)踐:很多情況不會設(shè)置one-to-many,如果要設(shè)置one-to-many可以設(shè)置為subselect。
? ? 6.2、基于Annotation的抓取
? ? 1、基于Annotation的many-to-one
session = HibernateUtil.openSession();/*** 對于Annotation的配置而言,默認(rèn)就是基于join的抓取的,所以只會發(fā)出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的配置沒有延遲加載,此時(shí)會把所有的關(guān)聯(lián)對象查詢出來,發(fā)出大量的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的默認(rèn)抓取策略是EAGER的,所以當(dāng)抓取Classroom* 時(shí)會自動(dòng)發(fā)出多條SQL去查詢相應(yīng)的Special,此時(shí)可以通過join fetch繼續(xù)完成對關(guān)聯(lián)的* 抓取,或者直接將關(guān)聯(lián)對象的fetch設(shè)置為LAZY,但是使用LAZY所帶來的問題是在查詢* 關(guān)聯(lián)對象時(shí)需要發(fā)出相應(yīng)的SQL,很多時(shí)候也會影響效率*/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;? ? 2、集合抓取
@OneToMany(mappedBy="classroom")@LazyCollection(LazyCollectionOption.EXTRA)@Fetch(FetchMode.SUBSELECT) //在Annotation中需要通過這種方式才能設(shè)置subselectpublic 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() {?
轉(zhuǎn)載于:https://my.oschina.net/pmos/blog/768310
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的Hibernate抓取策略的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。