Hibernate抓取策略

六、抓取策略:抓取策略主要是指獲取鏈接對象的策略。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() {
相關文章
相關標籤/搜索