SSH Hibernate框架特徵之延遲加載、對象持久化、緩存、關聯映射

延遲加載(懶加載)

   hibernate有些查詢API,在執行後並沒有立刻去查數據庫,而是在後續使用對象數據時纔會發送SQL加載數據。

 以下三種操作涉及延遲加載相對的是立刻性:

 1.load查詢 -- get 

 2.關聯查詢  -- join fetch

 3.query.iterator -- query.list

上述方法,使用中會經常遇到下面異常信息

    org.hibernate.LazyInitializationException: could not initialize proxy [cn.xdl.entity.Subject2#50] - no Session
解決方案:

 1.將session關閉推遲到對象加載完畢後(推薦)

 2.使用立即加載方法替代延遲加載方法

//請求--》StrutsFilter控制器--》Action--》Service--》Dao---》Result--》JSP/JSON--》關閉session--》輸出HTML/JSON響應結果

項目流程結構中,需要採用OpenSessionInView模式保持session在響應結果生成前處於打開莊濤,之後再關閉,最後輸出響應結果。可以通過以前過濾器、攔截器或AOP技術實現。

在Spring框架中提供了OpenSessionInViewFilter組件,可以直接配置使用即可。

例子:

public class TestLazy {
	@Test
	public void test1(){
		Session session = HibernateUtil.getSession();
		Subject2 load = session.load(Subject2.class, 50);//測試典型錯誤
		session.close();//session的關閉可以放到load查詢之後,報錯就會解決
		System.out.println("------------");
		System.out.println(load.getName());
	}
}	

對象持久化

Hibenrate框架可以爲應用程序構建一個持久層。

框架層級包含兩種:

表現層、控制層、業務層、持久層(用於DB數據訪問)

表現層、控制層、業務層、數據訪問層(用於DB數據訪問)

Hibernate中對象有以下三種狀態:

  1.臨時狀態(臨時對象)

          new Subject2()

          可以被垃圾回收機制回收

   2.持久狀態(持久對象)

          用session.get、load、sava、update等方法操作的對象。

          生命週期長,修改後會影響DB(數據庫)記錄。

          不會被垃圾回收機制回收

   3.遊離狀態/託管狀態

           session.clear()清除所有持久對象的狀態

           sesson.evict(持久對象名)清除指定的對象

           sesson.close()清除所有對象和資源的鏈接

           可以被垃圾回收機制回收

例子:

public class TestPersistent {
	@Test
	public void test1(){
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		Subject2 load = session.get(Subject2.class, 50);//持久層對象
		System.out.println(load.getId()+" "+load.getName());
		//再這加上session.clear()或 sesson.evict(load)方法。
		//則將load對象變爲遊離,不更改數據庫內容。
		load.setName("PYTHON");//更改數據庫記錄
		//session.flush();
		tx.commit();//內部先flush再提交事務
		session.close();	
	}
	@Test
	public void test2(){
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		Subject2 subject2 = new Subject2();//臨時對象
		subject2.setId(99);
		subject2.setName("JAVA");
		session.save(subject2);//提升爲持久對象,改變DB記錄
		subject2.setName("JAEE");//再次修改DB記錄
		tx.commit();//內部先flush再提交事務
		session.close();	
	}
}

Hibernate緩存

1.一級緩存

指的是session緩存,每個session對象都有一個緩存區,緩存獨享。session創建就分配空間,close關閉時釋放空間+關閉連接

自動放入緩存空間:get、load、save、update方法

手動維護和管理空間方法:clear、evict、close

優點:一個session查詢同一個對象多次,第一次查DB,後續從緩存獲取。

@Test
	public void test1(){
		Session session = HibernateUtil.getSession();
        //第一次查詢
		Subject2 load = session.get(Subject2.class, 50);//持久層對象
		System.out.println(load.getId()+" "+load.getName());
		//第二次查詢,此次是查緩存。
        Subject2 load2 = session.get(Subject2.class, 50);//持久層對象
		System.out.println(load.getId()+" "+load.getName());
		session.close();	
	}

2.二級緩存

指的是SessionFactory緩存,每個SessionFactory對象都有一個,由Factory創建出來的多個sesson共享緩存。Factory關閉會銷燬緩存

二級查詢默認關閉,需要使用時,得做很多設置開啓。

 --引入二級緩存工具包ehcache.jar和ehcache.xml配置文件

 --在hibernate.cfg.xml追加緩存配置參數

 --在映射描述信息追加@Cache 或在sql xml文件加入標籤< cache/>

3.查詢緩存

一級和二級緩存都只能緩存單個對象。如果有查詢結果集需要緩存,就需要採用查詢緩存。

查詢緩存默認關閉,使用時需要先開啓二級緩存,再開啓查詢緩存。

主要步驟如下:

 -開啓二級緩存

 -在hibernate.cfg.xml開啓查詢緩存參數

 -在查詢執行時,可以使用query.setCacheable(true);

Hibernate關聯映射

Hibernate中支持多種關聯映射,有一對多,多對一,多對多,一對一等關係類型。(多表聯合查詢)

表(主)   -----》表(外鍵)

DEPT       ------> EMP(DEPTNO)

一方   ------》多方,採用一對多關係加載

@OneToMany、<one-to-many>

一方 《------- 多方,採用多對一關係加載

@ManyToOne、<many-to-one>

多對多關係,需要3張表參與表示,使用@ManyToMany、<many-to-many>

一對一關係,可以通過主鍵對逐漸表示,也可以通過主鍵對外鍵(唯一性)表示。@OneToOne、<one-to-one>

 

一對多例子:

  1.再Direction.java中添加映射查詢的關係類型

//	@OneToMany(fetch=FetchType.EAGER) //是否延遲加載,默認延遲LAZY,EAGER爲飢餓
	@OneToMany //映射關係類型
	@JoinColumn(name="direction_id")//設置映射的字段,一般爲表中的外鍵
	private List<Subject> subjects;
	
	public List<Subject> getSubjects() {
		return subjects;
	}
	public void setSubjects(List<Subject> subjects) {
		this.subjects = subjects;
	}

2.對比hql語句和關聯映射。實現查詢id=1的方向信息並查方向id=1的學科信息。

public class TestAssocation {
	
	@Test //hql語句
	public void test1(){
		Session session = HibernateUtil.getSession();
		//查詢id=1的方向信息
		Direction d = session.load(Direction.class, 2);
		System.out.println(d.getId()+" "+d.getName());
		//查詢方向ID=1的學科信息
		String hql = "from Subject where directionId=?1";
		Query<Subject> query = session.createQuery(hql);
		query.setParameter(1, d.getId());
		List<Subject> subjects = query.getResultList();
		for(Subject s:subjects){
			System.out.println(s.getId()+" "+s.getName());
		}
		session.close();
	}
	
	@Test  //關聯映射
	public void test2(){
		Session session = HibernateUtil.getSession();
		//查詢id=1的方向信息
		Direction d = session.load(Direction.class, 2);
		System.out.println(d.getId()+" "+d.getName());
		//查詢方向ID=1的學科信息 
        //@OneToMany(fetch=FetchType.EAGER)開啓飢餓狀態,就算不查subjects也會生成語句,就 
        //是程序事先給你查好,等你使用。
//		for(Subject s:d.getSubjects()){
//			System.out.println(s.getId()+" "+s.getName());
//		}
		session.close();
	}

多對一例子使用xml文件配置:

1.再Direction.java中添加映射查詢的關係類型

        private Direction direction;
	
	public Direction getDirection() {
		return direction;
	}
	public void setDirection(Direction direction) {
		this.direction = direction;
	}

在Subject.hbm.xml中配置,外鍵是DIRECTION_ID。

<many-to-one name="direction"
			class="cn.xdl.entity.Direction" column="DIRECTION_ID"/>
	</class>

測試:通過學科信息加載相關的方向信息,多對一。

@Test
	public void test3(){
		Session session = HibernateUtil.getSession();
		//加載學科信息
		Subject subject = session.get(Subject.class, 1);
		System.out.println("學科名:"+subject.getName());
		//加載相關的方向信息
		System.out.println("方向信息:"+subject.getDirection().getName());
		session.close();
	}
	
	@Test
	public void test4(){
		Session session = HibernateUtil.getSession();
		//加載學科信息
		Query<Subject> query = session.createQuery(
			"from Subject s join fetch s.direction");
		List<Subject> list = query.getResultList();
		for(Subject subject:list){
			System.out.println(subject.getId()+" "+subject.getName()+" "+subject.getDirection().getName());
		}
		session.close();
	}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章