Hibernate fetch lazy cascade 的解釋

Hibernate 反向生成 產生BigInteger的解決方法:java

你應該用的Oracle吧,不要用裏面的number做爲主鍵,數據庫中使用long或者int.這樣反響工程的到的主鍵就是Long或者Intger類型的了。sql

問題解決了,只要給主鍵加個精度就行了使用Number(20)數據庫

 

1.cascade是否執行級聯操做

                     <set name="children" lazy="true" cascade="all">session

   在保存主表的時候,若是沒有保存從表信息,會拋出異常,若是設置了級聯關係,能夠自動先保存從表,在保存主表app

    all: 全部狀況下均進行關聯操做,即save-update和delete。
    none: 全部狀況下均不進行關聯操做。這是默認值。
    save-update: 在執行save/update/saveOrUpdate時進行關聯操做。
dom

2.inverse指定哪一方不控制關聯關係,通常在set上(1端不維護)

<set name="children" lazy="true" inverse="true">ide

3.lazy  :延遲加載

<class name=」mypack.Customer」 table=」CUSTOMER」 lazy=」false」>測試

laz    Lazy屬性爲false:當即檢索,一次性訪問有關聯關係的全部表。fetch

llaz   Lazy屬性爲true:(默認)延遲檢索,只訪問主表數據,從表數據不會當即訪問,只有當用到從表的時候會自動訪問。this

Lazy的有效期:只有在session打開的時候纔有效;session關閉後lazy就沒效了。

4.fetch :抓取策略,相似於lazy

<class name=」mypack.Customer」 table=」CUSTOMER」 fetch =」join」>

fetch="join」:相似於lazy=false,一次性查完

fetch="select」:相似於lazy=true

 

 

 

 

Hibernate 的延遲加載(lazy load)本質上就是代理模式的應用

實體是Employee和Department,它們之間是多對一的關係。

Department類:

Java代碼 複製代碼 收藏代碼
  1. public class Department { 
  2.     private int id; 
  3.     private String name; 
  4.  
  5.     public Department() { 
  6.     } 
  7.     public Department(String name) { 
  8.         this.name = name; 
  9.     } 
  10.     // getters and setters are omitted 
public class Department {
	private int id;
	private String name;

	public Department() {
	}
	public Department(String name) {
		this.name = name;
	}
	// getters and setters are omitted
}



Employee類:

Java代碼 複製代碼 收藏代碼
  1. public class Employee { 
  2.     private int id; 
  3.     private String name; 
  4.     private Department department; 
  5.  
  6.     public Employee() { 
  7.     } 
  8.     public Employee(String name) { 
  9.         this.name = name; 
  10.     } 
  11.     // getters and setters are omitted 
public class Employee {
	private int id;
	private String name;
	private Department department;

	public Employee() {
	}
	public Employee(String name) {
		this.name = name;
	}
	// getters and setters are omitted



Department.hbm.xml:

Xml代碼 複製代碼 收藏代碼
  1. <hibernate-mapping 
  2.     package="com.john.myhibernate.domain"> 
  3.  
  4.     <class name="Department"> 
  5.         <id name="id"> 
  6.             <generator class="native"/> 
  7.         </id> 
  8.         <property name="name" length="20" not-null="true"/> 
  9.     </class> 
  10. </hibernate-mapping> 
<hibernate-mapping
	package="com.john.myhibernate.domain">

	<class name="Department">
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="name" length="20" not-null="true"/>
	</class>
</hibernate-mapping>



Employee.hbm.xml:

Xml代碼 複製代碼 收藏代碼
  1. <hibernate-mapping package="com.john.myhibernate.domain"> 
  2.  
  3. <class name="Employee"> 
  4.     <id name="id"> 
  5.         <generator class="native"/> 
  6.     </id> 
  7.     <property name="name" length="20" not-null="true"/> 
  8.     <many-to-one name="department" column="department_id" class="Department" fetch="select"/> 
  9. </class> 
  10. </hibernate-mapping> 
<hibernate-mapping package="com.john.myhibernate.domain">

<class name="Employee">
	<id name="id">
		<generator class="native"/>
	</id>
	<property name="name" length="20" not-null="true"/>
	<many-to-one name="department" column="department_id" class="Department" fetch="select"/>
</class>
</hibernate-mapping>


many-to-one沒有inverse屬性,由於關係的維護是many的一方,不可能放棄對關係的維護。
many-to-one的lazy屬性有三個取值:false, proxy, no-proxy。

1. 測試cascade屬性:

Java代碼 複製代碼 收藏代碼
  1. public void testSaveCascade() { 
  2.     Session s = null
  3.     Transaction tx = null
  4.      
  5.     Department depart = new Department(); 
  6.     depart.setName("FCI"); 
  7.      
  8.     Employee em1 = new Employee("John"); 
  9.     em1.setDepartment(depart); 
  10.      
  11.     Employee em2 = new Employee("Lucy"); 
  12.     em2.setDepartment(depart); 
  13.      
  14.     try
  15.         s = HibernateUtil.getSession(); 
  16.         tx = s.beginTransaction(); 
  17.         s.save(em1); 
  18.         s.save(em2); 
  19.         tx.commit(); 
  20.     } catch (HibernateException e) { 
  21.         tx.rollback(); 
  22.         e.printStackTrace(); 
  23.     } finally
  24.         if (s != null
  25.             s.close(); 
  26.     } 
public void testSaveCascade() {
		Session s = null;
		Transaction tx = null;
		
		Department depart = new Department();
		depart.setName("FCI");
		
		Employee em1 = new Employee("John");
		em1.setDepartment(depart);
		
		Employee em2 = new Employee("Lucy");
		em2.setDepartment(depart);
		
		try {
			s = HibernateUtil.getSession();
			tx = s.beginTransaction();
			s.save(em1);
			s.save(em2);
			tx.commit();
		} catch (HibernateException e) {
			tx.rollback();
			e.printStackTrace();
		} finally {
			if (s != null)
				s.close();
		}
	}


結果是報org.hibernate.TransientObjectException異常,由於沒有保存Department實例。

能夠加cascade屬性,解決問題:

Xml代碼 複製代碼 收藏代碼
  1. <many-to-one name="department" column="department_id" class="Department" fetch="select" cascade="save-update"/> 
<many-to-one name="department" column="department_id" class="Department" fetch="select" cascade="save-update"/>



2. 測試fetch

Java代碼 複製代碼 收藏代碼
  1. Session s = null
  2.  
  3. s = HibernateUtil.getSession(); 
  4. Employee em = (Employee) s.get(Employee.class, 2); 
  5. System.out.println(em.getName()); 
  6. System.out.println(em.getDepartment()); 
Session s = null;
	
	s = HibernateUtil.getSession();
	Employee em = (Employee) s.get(Employee.class, 2);
	System.out.println(em.getName());
	System.out.println(em.getDepartment());


查詢語句以下:
Hibernate: select employee0_.id as id1_0_, employee0_.name as name1_0_, employee0_.department as department1_0_, employee0_.skill as skill1_0_, employee0_.sell as sell1_0_, employee0_.type as type1_0_ from Employee employee0_ where employee0_.id=?

Hibernate: select department0_.id as id0_0_, department0_.name as name0_0_ from Department department0_ where department0_.id=?
由於fetch設置爲select,因此對每一個實體,都分別用一個SELECT語句

若是把fetch設置爲join,也就是連表查詢,只使用一個SELECT語句。以下:
Hibernate: select employee0_.id as id1_1_, employee0_.name as name1_1_, employee0_.department as department1_1_, employee0_.skill as skill1_1_, employee0_.sell as sell1_1_, employee0_.type as type1_1_, department1_.id as id0_0_, department1_.name as name0_0_ from Employee employee0_ left outer join Department department1_ on employee0_.department=department1_.id where employee0_.id=?

3. 測試lazy
當fetch爲select時,設置lazy爲proxy或者no-proxy。

Xml代碼 複製代碼 收藏代碼
  1. <many-to-one name="department" column="department_id" class="Department" fetch="select" cascade="save-update" lazy="no-proxy"/> 
<many-to-one name="department" column="department_id" class="Department" fetch="select" cascade="save-update" lazy="no-proxy"/>


 

Java代碼 複製代碼 收藏代碼
  1. Session s = null
  2.  
  3. s = HibernateUtil.getSession(); 
  4. Employee em = (Employee) s.get(Employee.class, 2); 
  5. s.close(); 
  6. System.out.println(em.getName()); 
  7. System.out.println(em.getDepartment()); 
Session s = null;
	
	s = HibernateUtil.getSession();
	Employee em = (Employee) s.get(Employee.class, 2);
	s.close();
	System.out.println(em.getName());
	System.out.println(em.getDepartment());


結果是報org.hibernate.LazyInitializationException異常。
由於fetch爲select,並且lazy爲proxy或者no-proxy,因此開始僅僅查詢Employee,當須要用SELECT語句查詢Department時,Session已經關閉。

解決辦法:
1. 設置lazy爲false,hibernate會第一時間把Employee和Department查詢出來。
   若是fetch爲select,使用兩個SELECT查詢語句。
   若是fetch爲join,使用一個SELECT連表查詢語句。
2. 設置fetch爲join,這時無論lazy的取值,hibernate會進行連表查詢,把兩個實體都查詢出來。

 

Hibernate中的fetch, lazy, inverse和cascade

 

English Title:The Fetch in Hibernate, lazy, inverse and Cascade
1.fetch 和 lazy 主要用於級聯查詢(select) 而 inverse和cascade主要用於級聯增、加刪、除修

改(sava-update,delete)

2.想要刪除父表中的記錄,但但願子表中記錄的外鍵引用值設爲null的狀況:

父表的映射文件應該以下配置:

<set name="emps" inverse="false" cascade="all">

<key>

<column name="DEPTNO" precision="2" scale="0" />

</key>

<one-to-many class="com.sino.hibernate.Emp" />

</set>

inverse="false"是必須的,cascade無關緊要,而且子表的映射文件中inverse不必設置,cascade也能夠不

設置,若是設置就設置成爲cascade="none"或者cascade="sava-update"

<many-to-one name="dept" class="com.sino.hibernate.Dept" fetch="select" cascade="save-update">

<column name="DEPTNO" precision="2" scale="0" />

</many-to-one>

3.關於級聯查找對子表的持久化類進行查找的時候,會一塊兒把子表持久化類中的父表持久化類的對象一塊兒查詢

出來,在頁面中能夠直接取值的狀況:要把父表的映射文件中設置 lazy 屬性以下:

<class name="com.sino.hibernate.Emp" table="EMP" schema="SCOTT" lazy="false">

這樣就能夠直接在頁面中取值 (相似於這樣的取值 client.cmanager.id)若是沒有設置 lazy="false" 則會拋

出異常javax.servlet.ServletException: Exception thrown by getter for property cmanager.realName

of bean cl在Action中取值的話就會拋出 could not initialize proxy - the owning Session was closed

的異常

--------------------------------------------------------------------------------------------------

一、outer-join關鍵字(many-to-one的狀況)

outer-join關鍵字有3個值,分別是true,false,auto,默認是auto。
true: 表示使用外鏈接抓取關聯的內容,這裏的意思是當使用load(OrderLineItem.class,"id")時,Hibernate只生成一條SQL語句將OrderLineItem與他的父親Order所有初始化。

select * from OrderLineItem o left join Order p on o.OrderId=p.OrderId where o.OrderLineItem_Id=?

false:表示不使用外鏈接抓取關聯的內容,當load(OrderLineItem.class,"id")時,Hibernate生成兩條SQL語句,一條查詢OrderLineItem表,另外一條查詢Order表。這樣的好處是能夠設置延遲加載,此處要將Order類設置爲lazy=true。

select * from OrderLineItem o where o.OrderLineItem_Id=?
select * from Order p where p.OrderId=?

auto:具體是ture仍是false看hibernate.cfg.xml中的配置

注意:若是使用HQL查詢OrderLineItem,如 from OrderLineItem o where o.id='id',老是不使用外部抓取,及outer-join失效。

二、outer-join(集合)

因爲集合能夠設置lazy="true",因此lazy與outer-join不能同時爲true,當lazy="true"時,outer-join將一直是false,若是lazy="false",則outer-join用法與1同

三、HQL語句會將POJO配置文件中的關聯一併查詢,即便在HQL語句中沒有明確join

四、In HQL, the "fetch join" clause can be used for per-query specific outer join fetching. One important thing many people miss there, is that HQL queries will ignore the outer-join attribute you specified in your mapping. This makes it possible to configure the default loading behaviour of session.load() and session.get() and of objects loaded by navigating relationship. So if you specify

and then do
MyObject obj = session.createQuery("from MyObject").uniqueResult(); obj.getMySet().iterator().next();

you will still have an additional query and no outer-join. So you must explicily request the outer-join fetching:

MyObject obj = session.createQuery( "from MyObject mo left join fetch mo.mySet").uniqueResult();

Another important thing to know is that you can only fetch one collection reference in a query. That means you can just use one fetch join. You can however fetch "one" references in addition, as this sample from the Hibernate Docs demonstrates:

from eg.Cat as cat inner join fetch cat.mate left join fetch cat.kittens

We have once considered lifting this limitation, but then decided against it, because using more than one fetch-join would be a bad idea generally: The generated ResultSet becomes huge and is a major performance loss.

So alltogether the "fetch join" clause is an important instrument Hibernate users should learn how to leverage, as it allows tuning the fetch behaviour of a certain use case.

五、join fetchjoin 的區別

若是HQL使用了鏈接,可是沒有使用fetch關鍵字,則生成的SQL語句雖然有鏈接,可是並無取鏈接表的數據,仍是須要單獨的sql取數據,也就是 select a,b,d...中沒有鏈接表的字段

六、若是集合被聲明爲lazy=true,在HQL中若是顯式的使用 join fetch 則延遲加載失效。

七、在one-to-many的one端顯式設置fecth="join",則不管如何都採起預先抓取(生成一個SQl),延遲加載失效(生成兩個SQL)

八、many-to-one的延遲加載是在配置文件的class標籤設置lazy="true",one-to-many和many-to-many的延遲加載是在set標籤中設置lazy="true"。而one-to-one不僅要在calss標籤設置lazy="true",並且要在one-to-one標籤中設置constrained="true".

相關文章
相關標籤/搜索