hibernate經驗總結

一對一關係:
說明:Student和Certificate是一對一關係;
#1)基於主鍵的關聯
Student.hbm.xml(主):
<one-to-one name="cer" class="Certificate" fetch="join" cascade="all"/>
Certificate.hbm.xml(從):
<class name="Certificate" table="Certificate">
<id name="id">
    <generator class="forgien">
    <parm name="property>stu</parm>
    </generator>
</id>
<one-to-one name="stu" class="Student" constrained="true"/>
</class>
constrained="true"表示以stu的主鍵作爲外鍵;
#2)基於外鍵
Student.hbm.xml:
Student.hbm.xml同上面配置沒什麼區別;
Certificate.hbm.xml:
基於外鍵的跟語意不同了,這裏不是用<one-to-one>表示,而是用<many-to-one>表示;
<many-to-one name="stu" class="Student" unique="true" column="stu_id"/>
注意:a),unique="true"表示該many-to-one其實表達的是一對一關係;


一般是基於外鍵的,那麼在保存Certificate就要注意了;我是在Certificate中定義Student時,就初始化該對象了,Student stu=new Student();
然後創建Certificate時,cer.getStu().setId(stuId); serService.save(cer);

2,一對多關係:
#1)one-to-many
<bag name="replies" inverse="true" cascade="all-delete-orphan" lazy="true" order-by="createTime desc">
       <key column="topicId"></key>
       <one-to-many class="TopicReply"/>
</bag>
#2)many-to-one
<many-to-one name="user" class="UserMember" column="userId" unique="true">
</many-to-one>
#1)many-to-one默認就是延遲加載,所以在讀取多的時候,是不會讀取一方的;
#2)many-to-one是不能設置lazy="true"的;
#3)lazy屬性:
lazy只能設置爲false,proxy,no-proxy 3個值;默認爲proxy;
lazy設爲proxy,當child.getParent().getName()時,parent會被抓取;
若爲no-proxy,調child.getParent().getName()時,parent是不會被抓取的,同時這種方式需要編譯時字節碼增強,否則和proxy沒區別。
#4)fetch屬性:
設置<many-to-one>的fetch="join",只對get()查詢起作用,對list查詢沒起作用
在映射文檔中定義的抓取策略將會對以下列表條目產生影響:
1,通過get()或load()方法取得數據。
2,只有在關聯之間進行導航時,纔會隱式的取得數據。
3,條件查詢
4,使用了subselect抓取的HQL查詢
不管你使用哪種抓取策略,定義爲非延遲的類圖會被保證一定裝載入內存。注意這可能意味着在一條HQL查詢後緊跟着一系列的查詢。


3,多對多關係:
注意:多對多關係一般是雙向的,大多情況下並不需要該關係,我們可以把它們轉化爲一對多關係;
Student.hbm.xml
<set name="courses" table="student_course" cascade="save-update">
     <key column="stu_id"/> <!-- 注意,這裏的列名是該類對應的表的id
     <many-to-many class="Course" column="course_id"/>
</set>
這裏注意2個列名不要寫反了就是了;
******************************************************************
從hibernate3.0.5到hibernate3.2.5,中間已經經歷了很多個版本。我一看到那無數的bug fix就膽顫心驚,畢竟用hibernate支撐的系統是比較重要的業務,我很怕hibernate低版本出問題,從私心來說也想升到新版本,所以我很想說服領導採用最新的hibernate3.2.5。

代價:
從hibernate3.0.5升級到hibernate3.2.5,會對舊系統有影響,不是僅僅更換一個hibernate.jar包就行了,至少有以下幾點需修改:
1,Hibernate3.2.X的很多sql函數如count(), sum()的唯一返回值從Integer變爲Long
2,Hibernate3.2.X要求ehcache版本爲1.2以上.

好處:
hibernate3.2.x支持Annotation,這個對我們公司不具說服力,因爲我們公司習慣了hbm,不可能換。
有些流行的開源軟件也要求hibernate要3.2以上,這個有一定說服力.
那麼與hibernate3.0.5相比,hibernate3.2.x還具備哪些比較有說服力的優點呢?
******************************************************************
可以用fetch來代替outer-join

Criteria.setFetchMode(java.lang.String, FetchMode), Serialized Form

FetchMode.DEFAULT
FetchMode.SELECT--Equivalent to outer-join="false".
FetchMode.JOIN--Equivalent to outer-join="true".
FetchMode.EAGER:Deprecated. use FetchMode.JOIN
FetchMode.LAZY: Deprecated. use FetchMode.SELECT

left join fetch和left join是不一樣的,因爲前者多了個fetch,它採用了迫切左外連接,而後者僅僅是左外連接,這樣前者返回的就是一個對象,而後者返回的卻是一個對象數組.
===================================================
命名查詢(NamedQuery):
hibernateTemplate.findByNamedQuery("getTopic", userId);
注意:<query>和<sql-query>必須寫在<class>的後面,不然dtd會報錯誤.
<query name="cascadeFile2">
<![CDATA[
   from AlbumFile f left outer join f.folder fd where f.folder.id=?
]]>
</query>


<sql-query name="qryStatic">
        <return alias="t" class="cn.ccb.hrdc.qry.pojo.bo.QueryStaticBO">
            <return-property name="staticId" column="static_id"/>
            <return-property name="group" column="query_group"/>
            <return-property name="name" column="static_name"/>
        </return>

        SELECT t.static_id ,
        t.query_group ,
        t.static_name
        FROM qry_static t
        WHERE t.qry_id = :qry_id order by t.static_id asc
</sql-query>

String sql = "select z.xlr as {zb.xlr} from dd_jzxml_zb z";
//String sql = "select {zb.*} from dd_jzxml_zb zb";

try {
/*初始化,設置session*/
this.setUp();

List list = session.createSQLQuery(sql,"zb",BaseDdjzxmlzbPO.class).list();
/*資源釋放*/
this.tearDown();
}
執行的時候,報Caused by: java.sql.SQLException: 列名無效錯誤,
我把執行的sql打印了出來,是這樣的:
select z.xlr as XLR0_ from dd_jzxml_zb z
把這條SQL放到數據庫中是可以執行的,
將執行的SQL語句換爲註釋掉的那一個的話,可以正常執行的,不知道錯在那裏?

搞明白了,作爲載體類zb,他必須在hibernate的映射文件中進行配置,並且在其進行別名轉換時,必須把他所有配置過的屬性都進行轉換,
假如說zb這個類在映射時映射了xlr,mllx這兩個字段,在進行別名轉換時必須這麼寫
select z.xlr as {zb.xlr},z.mllx as {zb.mllx} from dd_jzxml_zb z
如果不寫全就會報列名無效的錯誤
===================================================
How can I find the size of a collection without initializing it?
Integer size = (Integer) s.createFilter( collection, "select count(*)" ).uniqueResult();

你可以統計查詢結果的數目而不必實際的返回他們:
( (Integer) session.iterate("select count(*) from ....").next() ).intValue();
===================================================
Hibernate的formula
<property name="currencyName" formula="(select cur.name from currency cur where cur.id= currencyID)"/>
currenyId是對象屬性(這也是該sql中唯一和對象相關部分,注意formula指定的是sql,不是hql)
1,必須有別名
2,整個sql必須被括號包括
===================================================
from User u where u.name in (:usernameList)
在 Hibernate 中通過這樣的方式將值注入到這個參數中:
List list=new ArrayList();
list.add(“jerry”);
list.add(“bluedavy”);
query.setParameterList(“usernameList”,list);
===================================================
每個持久化類都有一個標識屬性(實際上,這個類只代表實體,而不是獨立的值類型類,後者會被映射稱爲實體對象中的一個組件).這個屬性用來區分持久化對象:如果CatA.getId().equals(CatB.getId())結果爲true話,這兩個Cat就是相同的.
===================================================
uuid生成器:測試時建議使用,如果使用數據庫自動生成的數據類型的鍵值更好.
===================================================
每個session是一個獨立的單元操作.
===================================================
持久化標識(相當於主鍵),對於託管狀態的對象,Hibernate不保證任何持久化標識和java標識的關係.
===================================================
爲什麼po要繼承序列化,應該是hibernate要爲它們添加一些屬性吧.
===================================================
hibernate實體類中屬性不需要聲明爲public的,hibernate默認使用protected或private的get/set方法對,對屬性進行持久化.
===================================================
<proerty update="true" insert="true" ../>update,insert默認爲true;表示該屬性是否映射數據庫某個字段
若false,操作時對應的sql中沒屬性;
===================================================
cascade值:none,persist,merge,delete,save-udpate,replicate,lock,refresh,以及特別的值delete-orphan和all,並且可以用逗號來合併這些操作,比如cascade="persist,merge,evict"或cascade="all,delete-orphan"
===================================================
當持久化一個實例時,我們通過調用persist(),hibernate會自動把HashSet替換爲hibernate自己的set實現,
Cat cat=new Cat();
Set kittens=new HashSet();
kittens.add(cat);
cat.setKittens(kittens);
session.persist(cat);
kittens=cat.getKittens();//這裏OK,kittens collection is a Set
(HashSet)cat.getKittens();//Error!!
===================================================
session.save(cat);
session.flush();//force the sql insert
session.refresh(cat);//re-read the state (after the trigger executes);
任何時候都可以使用refresh()方法強制裝載對象和它的集合,如果你使用數據庫觸發器功能來處理對象的某些屬性,這個方法就很有用了.
===================================================
分頁:
Query q=ses.createQuery("from cat c");
q.setFirstResult(20);
q.setMaxResult(10);
List cats=q.list();
===================================================
如果你確定當前的session沒有包含與之具有相同持久性標識的持久實例,使用update().如果想隨時合併你的改動而不考慮session的狀態,使用merge().換句話說,在一個新的session中通常第一個調用的時update()方法,以便保證重新關聯脫管(detached)對象的操作首先被執行.
希望相關聯的脫管對象(通過引用'可到達'的脫管對象)的數據也要更新到數據庫時(並且也僅僅在這種情況),應用程序需要對該相關聯的脫管對象的單獨調用update(),當然這些可以自動完成,即通過使用傳播性持久化(transitive persistence);
===================================================
SaveOrUpdate()
Hibernate用戶曾要求一個既可以自動分配新持久化標識(identifier)保存瞬時(transient)對象,又可更新/重新關聯脫管(detached)實例的通用方法.saveOrUpdate()方法實現了這個功能.
以下場景會使用到update()或saveOrUpdate();
程序在第一個session中加載了對象,該對象傳到表現層併發生了改動,然後我們調用第二個session的update()方法來持久這些改動;
===================================================
EAGAIN和EINVAL。前者表示系統限制創建新的線程,例如線程數目過多了;後者表示第二個參數代表的線程屬性值非法。
===================================================
session clear 用於清空Session緩存,大量插入時可在插入中session.flush();session.clear(); 以免outofmemory

而evict用於清楚緩存中的某個對象session.evict(stu);SessionFactory.evict(Student.class,stu.getid())清除二級緩存
===================================================
組件(Component)映射:組件是把一張表拆成多個類
<class name="eg.Person" table="person">
    <id name="Key" column="pid" type="string">
        <generator class="uuid"/>
    </id>
    <property name="birthday" type="date"/>
    <component name="Name" class="eg.Name"> <!-- class attribute optional -->
        <property name="initial"/>
        <property name="first"/>
        <property name="last"/>
    </component>
</class>
人員(Person)表中將包括pid, birthday, initial, first和 last等字段。
===================================================
subClass是把一個類拆成多個表;
每個類分層結構一張表(Table per class hierarchy)
<class name="Payment" table="PAYMENT">
    <id name="id" type="long" column="PAYMENT_ID">
        <generator class="native"/>
    </id>
    <discriminator column="PAYMENT_TYPE" type="string"/>
    <property name="amount" column="AMOUNT"/>
    ...
    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
        <property name="creditCardType" column="CCTYPE"/>
        ...
    </subclass>
    <subclass name="CashPayment" discriminator-value="CASH">
        ...
    </subclass>
    <subclass name="ChequePayment" discriminator-value="CHEQUE">
        ...
    </subclass>
</class>
===================================================
10.4.1.3. 標量(Scalar)結果
查詢可在select從句中指定類的屬性,甚至可以調用SQL統計(aggregate)函數。 屬性或統計結果被認定爲"標量(Scalar)"的結果(而不是持久(persistent state)的實體)。

Iterator results = sess.createQuery(
        "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
        "group by cat.color")
        .list()
        .iterator();
       
while ( results.hasNext() ) {
    Object[] row = (Object[]) results.next();
    Color type = (Color) row[0];
    Date oldest = (Date) row[1];
    Integer count = (Integer) row[2];
    .....
}

 

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