今天呢,我開始鞏固下hibernate,當然還是跟着老師的講課班,不過第二次聽,那感覺就是不一樣。早在過去懞懞懂懂,或者根本不知道的知識,全部回顧瞭解了一遍。 正所謂:書讀百變,其義自見~! 太爽了,好開心~! 既然學,那就認真點。 此貼陸續把每次鞏固的收穫寫上來的。
hibernate建立數據的的映射是完全可以通過eclips自動導入實現的,不過,基礎還是要學的。知其解決方法,也要知其理纔行~!
(~ o ~)~zZ 以下是收穫:
---------------------------------------------------------------------------------------------
xml形式的實體化映射:
*.hbm.xml
<hibernate-mapping>
<class name="實體化類名" table="表名">
<id> 定義一個單主鍵,一個字段 屬性作爲實體類的主鍵
<composite-id> 複合主鍵,多個字段 一組屬性作爲主鍵的定義方式 (主鍵類,實現序列化接口)
<property> 字段---》屬性的映射
</class>
</hibernate-mapping>
練習:
emp-->dept 多對一 實現級聯,添加,刪除操作
首先寫好emp和dept實體化類 emp爲主表實體化類,所以emp有dept類的對象作爲屬性
接着寫映射文件.hbm.xml
emp.hbm.xml如下:
dept.hbm.xml 如下:
注意了:
在寫pojo類時,*.hbm.xml寫完之後,
還要將hibernate.cfg.xml之後加入
<mapping resource="cn/com/vo/Emp.hbm.xml" />
<mapping resource="cn/com/vo/Dept.hbm.xml" />類似這樣的地址,實現pojo類在hibernate中的關係映射
(自動通過數據庫導入的pojo類,eclips會自動將其地址加在hibernate.cfg.xml中
hbm2ddl.auto 這個在hibernate.cfg.xml中若是設置爲true,則會根據映射關係在數據庫中建立相應的table,假如數據有了~就不會建了。
cascade 有以下取值:
all : 所有操作都傳遞到相關聯的對象
save-update 保存和更新傳遞到相關聯的對象
delete 刪除操作傳遞到相關聯的對象
delete-orphan : 所有操作都傳遞到相關聯的對象 並刪除不再與父對象關聯的對象。
-----------------------------------------------------------------------------------------------------------------------------------------
級聯刪除這要找到數據庫裏的對象
用Emp emp=(Emp)session.get(Emp.class,7935");
session.delete(emp);
這樣會把emp表和相關聯的dept表中的數據都刪掉
-----------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------------
從表---主表, 一對多的關係 (Onetomany)
hibernate 之中的集合有 list,map,set,bag 在一對多中經常用的時set--原理:去空值,去重複 (難怪呢)
類之間用set實現1 對n
配置上,
<one-to-many>
<set 的屬性有 :>
name 屬性名
table 基於關聯表的一對多關係
lazy="true/false"是否使用延遲加載技術——不錯!true,沒有用到關聯表,則不會把關聯表的信息搜出來,加載到緩存中,反之則會嚴重影響其性能~ 平時就要檢查設置爲true hibernate 3.0以後基本默認都是true
inverse(true/false) 關聯關係由哪一方來維護 true--會根據從表實體類維護 false--會根據主表實體類維護
out-join
fetch
orderby 對關聯表排序
---
<key column="設置從表的外鍵字段'></key>
<one-to-many class="從表實體類"/>
dept和emp是 1對多的關係
1 將dept實體類中加入emps 的set集,然後get/set方法
只需要將dept.hbm.xml改下即可:
----------------------------------------------------------------------------------------------------------------------------------------------
<many-to-many> 多對多
例子:學生表 關聯表 老師表
<set >的屬性
name
table 中間表
<key column="中間表的與當前表所映射的外鍵字段">
<many-to-many culumn="中間表與關係的另一個表所建立的關聯字段">
這裏給出一個寫在一起的many-to-many.hbm.xml
9.28 Hibernate 特殊表的關聯 和 繼承在hibernate 實現持久化的作用
1對1(外主)
1對多(中間表的)
繼承,通過繼承實現hibernate數據化的持久性操作
1對1關係
第一種情況:a表引用b表的主鍵做外鍵具有唯一性約束
一個人對應一個地址
person address
-------------------
p_id a_id
p_name a_name
a_id 外鍵+了唯一性約束
<many-to-one>
將many改成unique="true"
這個還是比較容易理解的。
第二中情況:a表引用b表的主鍵,在a表中既做主鍵,也做外鍵
person address
----------------
p_id a_id( 它是引用p_id的外鍵)
p_name a_name
<one-to-one name="person" constrained="true"></one-to-one>只對主鍵進行描述
<one-to-one name="關聯屬性"> 在hibernate機制上描述兩個實體1對1的關係
在操作時基於兩個標的主鍵進行關聯操作
基於該關係生成外鍵約束,或在某一鍵上加上某一屬性
將contraonted="true"基於關係生成外鍵約束
column 描述關聯字段(外鍵1對1關係,需要從主表這邊描述的時候)
在它的<id 屬性上>
<genertor ,,
</id>
繼承 在 hibernate中的作用
單表繼承
在一個表中,通過一個標識來區分不同的數據類型,如type字段
用戶有:學生,老師的例子不錯啊
type屬性
用
<id...>
<discrimininator column="type類型的字段名 user_type">
</discrimininator>
<property...>
<subclass name="子類的名稱" discriminator-value="標識字段爲何值用該子類">
<property name="teacherPhoto" column="teacher_photo"></property>
</subclass>
繼承在hibernate中的強勢應用。這是單表的繼承。
(類之間要有繼承user被student 和teacher繼承,配置如上)
關聯表的繼承。
用戶表是雙方都有的信息
學生,老師是自己獨有的基礎信息表
用戶
|
|
----------------------------
學生 老師
配置中用<joined-subclass>---繼承關聯
<joined-subclass name="類名" table="表名">
<key clumn="關聯外鍵字段"/>
<property name="" clumn=""/>
<many-to-one>..</...>
</joined-subclass>
在上面的特殊表關聯中,要體會其原理,還有對 unique="true"的理解。。這個理解真的挺重要的。
-------------------------------------------------
會用hibernate做項目和你懂hibernate完全是兩個概念。。 是的,知道原理,寫起代碼不再是機械式的填充。
--------------------------------------------------------------------------------------------------------------------------------
hibernate 持久化對象的生命週期
session作爲持久化對象 有3個狀態:
1 瞬時狀態--由new關鍵字創建生成的對象狀態,這種對象只會在內存中存在
狀態沒有和數據庫同步
session中沒有持久該對象的引用。(數據對象有可能丟失)
2 持久狀態--對象是由session創建生成(如session.save() session.update())
session持有該對象引用後,將其狀態也入到數據庫中
3 離線狀態--原本爲持久狀態的對象,因session.close() 即 session資源的關閉或者session清空實體對象的 引用,導致該對象不再由session管理,稱作離線狀態
new(新生)----get/load()--》持久狀態 session.load是按主鍵檢索數據,創建持有對象,以及持久對象的代理對象,返回的是代理對象。
|
|
|
瞬時狀態 ----save(),saveOrUpdate() ----》持久狀態 ---evict()清除指定類型id clear()清除所有 close()-----》離線狀態
離線對象---update(),saveOrUpdate(),lock()-->持久對象-----delete()--》瞬時狀態
hibernate每一個類都要配置一個id,表示唯一性。那麼session的表示id也只有一個,因爲唯一性的存在,反之,數據的維護變的相當混亂
---------------------------------------------------------------------------------
Hibernate 檢索語言 Hql
"from 類名 where 屬性名=? ";將查詢的結果封裝成類名所對應的類實例對象
hql的關聯查詢:
select a.dept.deptno from Emp a 會根據實體類之間的關聯,自動生成多表關聯的sql
from Emp a where a.dept.dname=? hql果然強大~!
Query query=session.createQuery("from Emp a where a.dept.dname=?");
query.setString(0,"教育部");
List<Emp> result=query.list();
在hql中一旦出現select子句,它肯能查詢出的結果不按照from的類名封裝對象,而是將結果放在Object[]中
Query query=session.createQuery("select a.dept.dname.a.sal from Emp a where a.dept.dname=?");
query.setString(0,"教育部");
List<Object[]> result=query.list();
如果這樣你用着還不是很爽,可以利用hibernate實現有參的構造函數
Query query=session.createQuery("select new Emp(a.dept.dname.a.sal) from Emp a where a.dept.dname=?");//前提Emp有這樣一個構造函數。
query.setString(0,"教育部");
List<Emp> result=query.list();
------------------------hibernate的強大在於你可以根據自己的需求設計出合理的方式完成檢索操作~贊一個!
hql函數的使用:
聚合函數:avg() sum() max() count()
查詢關鍵字:distinct
集合操作函數:size(),minelement(),minindex(),maxindex()
Orderby 子句 group by 子句
例子:"from Dept a where size(a.emps)>=2";
---------------------------------------------------
連接查詢
inner join 基於關聯屬性經行操作 inner join fetch
Query query=session.createQuery("from Dept dept inner join fetch dept.emps");
query.list();
Left outer join left outer join fecth
Right outer hoin
Fetch只對inner join 和Left join 有效,Right outer join返回的是數組
-----------------------------
Query query=session.getNamedQuery("leftjoin");//這個是在xml的配置文件中寫的cdata..這個問題解決就好了
query.list();
---------------------------------------------------------------------------------------------------------------
補充的知識:
標準查詢
SQL查詢
附:攔截器
驗證器
鎖策略--樂觀鎖,悲觀鎖的操作實現
標準查詢---面向對象技術//這個沒有sql,或者hql語句靈活,也沒他們可讀性強。這種語言只能作爲輔助
sql---------->對象的方法
Criteria cr=session.createCriteria(Emp.class);
cr.add(Expression.gt("sal",1000));//Expression是一個接口關於Criteria
List result=cr.list();
Emp emp=null;
for(int i=0;i<result.size();i++){
emp=(Emp)result.get(i);
}
標準查詢是基於Critera.add(查詢條件) 查詢條件由Experssion生成對象,根據不同的條件方法調度,生成對應的查詢條件 Experssion方法有很多(eq,gt,like等)
-------------------
SQl 查詢
sql語句的通用性很差。不同的版本oracle會使用到不同的sql語句語法。容易出錯。 瞭解下了
而HQL則無需考慮這些。
SQLQuery sqlQuery=session.createSQLQuery("select ename,job,sal from emp where deptno=?");
Query query=session.getNamedQuery("leftjoin");//這個是在xml的配置文件中寫的cdata..
sqlQuery.setInteger(0,10);
List list=sqlQuery.list();
-----------------------
攔截器--設置在sessionFactory之上,對session的持久化操作就行攔截
EmptyInterceptor 是個抽象類,我們的類需要實現它。
加入方法用eclipse的 overwrite中找到對應的方法即可!!!
onDelete()
onLoad()
onSave()
這是繼承EmptyInterceptor 的類例如MyInterceptor
那麼在實現類中 加入
Configuration configuration = new Configuration().configure();
configuration.setInterceptor(new MyInterceptor())//這個是加入的。。!!!
SessionFactory sessionFactory = configuration.buildSessionFactory();
------------------------------------
驗證器
驗證接口--用於在數據的添加,修改時,在持久化操作之前,對數據有效性驗證。
validator---validate() throws ValidationFailure
validate()可以終止原有的持久化操作。
-----------------------------------
鎖策略
鎖機制 ---在併發訪問下,保護資源有序的被使用
樂觀鎖 悲觀鎖
Hibernate 鎖策略
Hibernate 內部鎖機制
LockMode.NONE 無鎖機制
LockMode.WRITE hibernate 進行保存和更新時自動使用的鎖機制。
LockMode.READ hibernate 讀取紀錄時的機制
悲觀鎖
整個數據處理過程中,將數據處於鎖定
狀態。悲觀鎖的實現,往往依靠數據庫提供的鎖機制
LockMode.UPGRADE
LockMode.UPGRADE_NOWAIT
//相當於SQL(for update 中的 wait 或者nowaite)
實現機制如下:
Criteria.setLockMode
Query.setLockMode(Strng指hql語句中實體類的別名,LockMode.UPGRADE);
例如:
Query query=session.createQuery("from Emp a");
Query.setLockMode(a,LockMode.UPGRADE_NOWAIT);
Emp emp=(Emp)session.load(Emp.class,1,LockMode.UPGRADE_NOWAIT);//悲觀鎖
session.lock (實例對象,LockMode.READ);
缺點:資源開銷大,一般不用這種,通常推薦使用樂觀鎖機制
樂觀鎖
更加寬鬆的加鎖機制,悲觀鎖對長事務而言,開銷往往無法承受;避免死鎖。
實現機制:
Hibernate在o/R中映射特殊字段<timestamp> 或者<version>
採用特殊字段來做判斷,平時操作不等待,但是保存或者更新時會進行判斷。
Version
Dirty
ALL
主要介紹 Version
官方推薦的樂觀鎖實現策略,廣泛使用,具有經驗可借鑑性
實現舉例:在每一次進行讀取操作時取出版本號,在進行更新時同時刷新版本號,更新時只能更新低版本的數據,從而完成鎖策略。 Hibernate 的 Session 會在等待用戶交互時 ,Session 斷開數據庫連接。在整個應用事務過程中, Hibernate 使用單例 Session 和單例類來實現。
使用方法:
<class name="UserVo" table="uservo" schema="SPRINGDEV" optimistic-lock="version">
< 主鍵 >
<version name="version" column="version" type="java.lang.Integer" />
同時數據庫表中增加字段 version ,version無須設置,它會隨着操作自動增加。
總結:在一般性的事務中,大可將鎖機制拋開不用,這樣不可否認增加了複雜性,你不得不面對不少的版本異常信息,只有在涉及關鍵業務如進行網上購物的付款等就必須進行加鎖管理,當然推薦基於 version 的樂觀鎖管理。
-------------------------------------------------------------------------------------------------------------
hibernate 空值異常
字段 ---》屬性(基本數據類型)(包裝類型,字符,日期)
基本數據類型(int,double,char等)
優:性能好
缺點:不能接受空字段的值
包裝類:如Double,String,Date,Integer(就是java.lang.*這種包裝類)
優:能包裝空值在內的所有有效數值
缺點:資源開銷大
提示:如果數據封裝不上pojo類,有可能就是數據類型選擇的錯誤!
----------------------------------------------------------------------------
這樣的錯誤:
<c:forEach var="dt" items="${requestScope.list}">
<tr>
<td>${dt.empno}</td>
<td>${dt.ename}</td>
<td>${dt.job}</td>
<td>${dt.sal}</td>
<td>${dt.dept.deptno}</td>//可以顯示的,它在emp表中作爲外鍵<many-to-one name="dept".. ><column
name="DEPTNO"/></many-to-one>
<td>${dt.dept.dname}</td>//這個不可以顯示,它跟emp無任何關聯。是dept獨有的。會報session已經關閉。以下
有解決辦法。
</tr>
</c:forEach>
session是線程不安全,不能被多個線程同時使用
web-線程->請求處理 一個請求可以對應一個session線程。
利用java.lang.ThreadLocal 會爲每一個當前線程分配一個獨立的存儲空間
Map<key,value>會爲這一個線程保存獨有的線程信息
以下爲代碼:
--------------------------------------------------------
view plaincopy to clipboardprint?
package cn.com.csuinfosoft.hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static SessionFactory sessionFactory = null;
private static ThreadLocal threadLocal = new ThreadLocal();
static {
try {
Configuration config = new Configuration().configure();
sessionFactory = config.buildSessionFactory();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static Session getSession() {
Session session = (Session)threadLocal.get();//獲取當前線程對應的內存空間中,存儲的對象
if(session == null) {
session = sessionFactory.openSession();
threadLocal.set(session);
}
return session;
}
public static void closeSession() {
Session session = (Session)threadLocal.get();
if(session != null) session.close();
threadLocal.set(null);
}
}
package cn.com.csuinfosoft.hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static SessionFactory sessionFactory = null;
private static ThreadLocal threadLocal = new ThreadLocal();
static {
try {
Configuration config = new Configuration().configure();
sessionFactory = config.buildSessionFactory();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static Session getSession() {
Session session = (Session)threadLocal.get();//獲取當前線程對應的內存空間中,存儲的對象
if(session == null) {
session = sessionFactory.openSession();
threadLocal.set(session);
}
return session;
}
public static void closeSession() {
Session session = (Session)threadLocal.get();
if(session != null) session.close();
threadLocal.set(null);
}
}
//在實現類中通過 Session session=HibernateUtil.getSession()這樣得到的session是在同一個請求中保持不變的
。
然後當我們需要在請求結束關閉這樣個一session可以寫filter文件:
-------------------------
view plaincopy to clipboardprint?
package cn.com.csuinfosoft.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import cn.com.csuinfosoft.hibernate.HibernateUtil;
public class HibernateFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
try {
System.out.println("============ Filter try ====== Thread:" +
Thread.currentThread().getName());
filterChain.doFilter(request, response);
} finally {
System.out.println("============ Filter finally ======Thread:" +
Thread.currentThread().getName());
HibernateUtil.closeSession(); //每次請求結束前關閉Session
}
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
package cn.com.csuinfosoft.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import cn.com.csuinfosoft.hibernate.HibernateUtil;
public class HibernateFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
try {
System.out.println("============ Filter try ====== Thread:" +
Thread.currentThread().getName());
filterChain.doFilter(request, response);
} finally {
System.out.println("============ Filter finally ======Thread:" +
Thread.currentThread().getName());
HibernateUtil.closeSession(); //每次請求結束前關閉Session
}
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
最後將這樣一個filter配置在web.xml中,是相當容易的。
----------------------------
補充:SessionFactory可以在監聽器控制下, 是要在程序卸載的時候關閉掉。
在過去所學的線程中Thread 中獲得當前線程方法爲currentThread()
hibernate的配置優化
<property name="jdbc.batch_size">30</property> 這個用於管理數據庫批量處理的,如批量刪除
<property name="jdbc.fetch_size">50</property> 在jdbc抓取數據時採用分批抓取,一次可以抓取50條
做一個簡單 批量刪除 實現,不是很難哦!
----------------------------------------------------------------------------------------------------------------
不懂得問題:
<class name="UserVo" table="uservo" schema="SPRINGDEV" optimistic-lock="version">
< 主鍵 >
<version name="version" column="version" type="java.lang.Integer" />
</class>
解釋下schema="SPRINGDEV" 和optimistic-lock="version":
1)其中<class name="UserVo" table="uservo" schema="SPRINGDEV" optimistic-lock="version">中的schema="SPRINGDEV"表示數據庫的用戶名。如果當前鏈接數據庫的用戶名稱不是SPRINGDEV的話,實際操作中還是會用SPRINGDEV這個用戶來操作。這就會產生一系列問題。
2)optimistic-lock屬性有如下可選取值:
? none 無樂觀鎖
? version 通過版本機制實現樂觀鎖
? dirty 通過檢查發生變動過的
-------------------------------------------------------------------------------------------------------------------------
Hibernate 關閉sessionFactory :
關閉sessionFactory是應在服務器被關閉,程序被卸載時關閉,所以需要寫一個sessionFactory特有的監聽類,當服務器被關閉時,自動關閉sessionFactory.
寫個監聽類 實現ServletContextListener 在該類中關閉關閉sessionFactory ,以下就是:
將監聽類配置在web.xml 中
<listener>
<listener-class>cn.com.csuinfosoft.listener.HibernateListener</listener-class>
</listener>
-------------------------------------------------------------------------------------
---------------------------------------------------------------以下轉載的,一些關鍵字的注意,配合着學習:
重點學習 Hibernate fetch lazy cascade inverse 關鍵字
Hibernate最讓人頭大的就是對集合的加載形式。
書看了N次了,還是沒有真正理解Hibernate。所以下午專門做了下測試,對配置文件的意思加深了認識。
假設有兩個表,Photos(一) --- picture(多)Photo包含picture集合
結論1: HQL代碼 > fetch(配置) > lazy (配置)
結論2: 默認 lazy="true"
結論3: fetch 和 lazy 主要是用來級聯查詢的, 而 cascade 和 inverse 主要是用來級聯插入和修改的
fetch參數指定了關聯對象抓取的方式是select查詢還是join查詢,select方式時先查詢返回要查詢的主體對象(列表),再根據關聯外鍵id,每一個對象發一個select查詢,獲取關聯的對象,形成n+1次查 詢; 而join方式,主體對象和關聯對象用一句外鍵關聯的sql同時查詢出來,不會形成多次查詢。
如果你的關聯對象是延遲加載的,它當然不會去查詢關聯對象。 另外,在hql查詢中配置文件中設置的join方式是不起作用的(而在所有其他查詢方式如get、criteria或再關聯獲取等等都是有效的),會使用select方式,除非你在hql中指定join fetch某個關聯對象。fetch策略用於定義 get/load一個對象時,如何獲取非lazy的對象/集合。 這些參數在Query中無效。
在某種特殊的場合下,fetch在hql中還是起作用的。
例如
現有message(回帖)-->topic(主貼)-->forum(版塊) 的多級many-to-one結構:
第一級:message-->topic many-to-one配置lazy="false" fetch="join"
第二級:topic-->forum many-to-one配置lazy="false" fetch="join"
這時如果"from message",則第二級:topic-->forum中的fetch策略會起作用
查詢抓取(默認的)在N+1查詢的情況下是極其脆弱的,因此我們可能會要求在映射文檔中定義使用連接抓取:
<set name="permissions"
fetch="join">
<key column="userId"/>
<one-to-many class="Permission"/>
</set
<many-to-one name="mother" class="Cat" fetch="join"/>
在映射文檔中定義的抓取策略將會有產生以下影響:
通過get()或load()方法取得數據。
只有在關聯之間進行導航時,纔會隱式的取得數據(延遲抓取)。
條件查詢
在映射文檔中顯式的聲明 連接抓取做爲抓取策略並不會影響到隨後的HQL查詢。
通常情況下,我們並不使用映射文檔進行抓取策略的定製。更多的是,保持其默認值,然後在特定的事務中, 使用HQL的左連接抓取(left join fetch) 對其進行重載。這將通知 Hibernate在第一次查詢中使用外部關聯(outer join),直接得到其關聯數據。 在條件查詢 API中,應該調用 setFetchMode(FetchMode.JOIN)語句。
其實這並不能說明hql能夠按照配置文件設置的join進行抓取,這時 第二級:topic-->forum 的抓取其實已經和hql沒有關係了,因爲前面已經產生了另一個select方式的抓取語句。
而是對象的關聯獲取,假如查詢message時topic是設置爲延遲加載的,那麼在後面獲取message.topic時,如topic.forum不延遲加載,那麼topic-->forum會實現配置的join方式的抓取,這個顯然和hql查詢沒有關係。
結論4: 如果你是用spring來幫你管理你的session, 並且是自動提交,延遲加載就等於沒加載~_~(當然
除非你手動重新打開session然後手動Hibernate.initialize(set);然後關閉session.
結論5: cascade主要是簡化了在代碼中的級聯更新和刪除。
j結論6:老爸可以有多個孩子,一個孩子不能有多個老爸,而且老爸說的算, 孩子圍着老爸轉。
所以Photos老爸要有權力所以 cascade 這個關鍵子都是送給老爸的, 也就是級聯更新,
老爸改姓了,兒子也得跟着改,呵呵。“不然,就沒有零花錢咯”。
而Picture兒子整體捱罵,但是還是要維護父子之間良好的關係,對老爸百依百順,所
以老爸就說,兒子,“關係,由你來維護(inverse="true") ,不然就不給零花錢。呵。”。
<set name="pictures" inverse="true" cascade="all">
<key>
<column name="photosid" not-null="true" />
</key>
<one-to-many class="girl.domain.Picture" />
</set>
測試代碼:
Photos p = ps.getById(1);
Set<Picture> set = p.getPictures();
for(Picture pic : set){
System.out.println(pic.getId());
}
配置文件的一部分:
<set name="pictures" inverse="true" cascade="all" >
<key>
<column name="photosid" not-null="true" />
</key>
<one-to-many class="girl.domain.Picture" />
</set>
測試過程會對配置文件不斷修改:並且從來不曾手動重新打開session
測試結構:
當配置條件爲 lazy=true 一句查詢 測試代碼中沒有調用getPicture() 正常
Hibernate: select photos0_.id as id0_0_, photos0_.userid as userid0_0_, photos0_.typeid as typeid0_0_, photos0_.name as name0_0_, photos0_.createtime as createtime0_0_, photos0_.description as descript6_0_0_, photos0_.faceid as faceid0_0_, photos0_.uri as uri0_0_ from super.photos photos0_ where photos0_.id=?
lazy=true 一句查詢 有getPicture()
Hibernate: select photos0_.id as id0_0_, photos0_.userid as userid0_0_, photos0_.typeid as typeid0_0_, photos0_.name as name0_0_, photos0_.createtime as createtime0_0_, photos0_.description as descript6_0_0_, photos0_.faceid as faceid0_0_, photos0_.uri as uri0_0_ from super.photos photos0_ where photos0_.id=?
lazy=true 一句查詢 有getPicture() 並且訪問了裏面的元數Picture 且有異常拋出
Hibernate: select photos0_.id as id0_0_, photos0_.userid as userid0_0_, photos0_.typeid as typeid0_0_, photos0_.name as name0_0_, photos0_.createtime as createtime0_0_, photos0_.description as descript6_0_0_, photos0_.faceid as faceid0_0_, photos0_.uri as uri0_0_ from super.photos photos0_ where photos0_.id=?
lazy="false" 兩句查詢 肯定沒問題,因爲全部數據都個查了出來 所以怎麼調用都正常
Hibernate: select photos0_.id as id0_0_, photos0_.userid as userid0_0_, photos0_.typeid as typeid0_0_, photos0_.name as name0_0_, photos0_.createtime as createtime0_0_, photos0_.description as descript6_0_0_, photos0_.faceid as faceid0_0_, photos0_.uri as uri0_0_ from super.photos photos0_ where photos0_.id=?
Hibernate: select pictures0_.photosid as photosid1_, pictures0_.id as id1_, pictures0_.id as id2_0_, pictures0_.photosid as photosid2_0_, pictures0_.name as name2_0_, pictures0_.clicked as clicked2_0_, pictures0_.uploaddate as uploaddate2_0_, pictures0_.size as size2_0_, pictures0_.description as descript7_2_0_, pictures0_.uri as uri2_0_ from super.picture pictures0_ where pictures0_.photosid=?
fetch="join" 一句查詢 效果 == lazy="false" 呵呵,哪個效率高,我就不知道了。。。。。。。。。。。
Hibernate: select photos0_.id as id0_1_, photos0_.userid as userid0_1_, photos0_.typeid as typeid0_1_, photos0_.name as name0_1_, photos0_.createtime as createtime0_1_, photos0_.description as descript6_0_1_, photos0_.faceid as faceid0_1_, photos0_.uri as uri0_1_, pictures1_.photosid as photosid3_, pictures1_.id as id3_, pictures1_.id as id2_0_, pictures1_.photosid as photosid2_0_, pictures1_.name as name2_0_, pictures1_.clicked as clicked2_0_, pictures1_.uploaddate as uploaddate2_0_, pictures1_.size as size2_0_, pictures1_.description as descript7_2_0_, pictures1_.uri as uri2_0_ from super.photos photos0_ left outer join super.picture pictures1_ on photos0_.id=pictures1_.photosid where photos0_.id=?
不加fetch="join" 一句查詢 沒有getPicture() 正常
Hibernate: select photos0_.id as id0_0_, photos0_.userid as userid0_0_, photos0_.typeid as typeid0_0_, photos0_.name as name0_0_, photos0_.createtime as createtime0_0_, photos0_.description as descript6_0_0_, photos0_.faceid as faceid0_0_, photos0_.uri as uri0_0_ from super.photos photos0_ where photos0_.id=?
不加fetch="join" 一句查詢 有getPicture() 正常
Hibernate: select photos0_.id as id0_0_, photos0_.userid as userid0_0_, photos0_.typeid as typeid0_0_, photos0_.name as name0_0_, photos0_.createtime as createtime0_0_, photos0_.description as descript6_0_0_, photos0_.faceid as faceid0_0_, photos0_.uri as uri0_0_ from super.photos photos0_ where photos0_.id=?
不加fetch="join" 一句查詢 有getPicture() 並且訪問裏面的元素Picture的ID 有異常拋出
Hibernate: select photos0_.id as id0_0_, photos0_.userid as userid0_0_, photos0_.typeid as typeid0_0_, photos0_.name as name0_0_, photos0_.createtime as createtime0_0_, photos0_.description as descript6_0_0_, photos0_.faceid as faceid0_0_, photos0_.uri as uri0_0_ from super.photos photos0_ where photos0_.id=?
來個兩兵交戰 fetch="join" lazy="true" 呵呵 結果,一句查詢, 結構正常 所以就當lazy不存在好了。 看來fetch 是老大。、、、、、、、、、、、、、
Hibernate: select photos0_.id as id0_1_, photos0_.userid as userid0_1_, photos0_.typeid as typeid0_1_, photos0_.name as name0_1_, photos0_.createtime as createtime0_1_, photos0_.description as descript6_0_1_, photos0_.faceid as faceid0_1_, photos0_.uri as uri0_1_, pictures1_.photosid as photosid3_, pictures1_.id as id3_, pictures1_.id as id2_0_, pictures1_.photosid as photosid2_0_, pictures1_.name as name2_0_, pictures1_.clicked as clicked2_0_, pictures1_.uploaddate as uploaddate2_0_, pictures1_.size as size2_0_, pictures1_.description as descript7_2_0_, pictures1_.uri as uri2_0_ from super.photos photos0_ left outer join super.picture pictures1_ on photos0_.id=pictures1_.photosid where photos0_.id=?