先給出一份常見的持久化類配置文件大概熟悉一下
- <strong><spanstyle="font-size: 18px;"><hibernate-mapping>
- <classname="zyw.app.domain.Person1">
- <idname="id"type="java.lang.Integer">
- <generatorclass="identity"/>
- </id>
- <propertyname="name"type="java.lang.String"/>
- <propertyname="age"type="java.lang.Integer"/>
- <listname="schools"inverse="false"table="school"lazy="true">
- <key>
- <columnname="person_id"/>
- </key>
- <list-indexcolumn="schools_order"/>
- <elementtype="java.lang.String">
- <columnname="school_name"/>
- </element>
- </list>
- </class>
- </hibernate-mapping></span></strong>
<hibernate-mapping> <class name="zyw.app.domain.Person1"> <id name="id" type="java.lang.Integer"> <generator class="identity" /> </id> <property name="name" type="java.lang.String"/> <property name="age" type="java.lang.Integer"/> <list name="schools" inverse="false" table="school" lazy="true"> <key> <column name="person_id" /> </key> <list-index column="schools_order"/> <element type="java.lang.String"> <column name="school_name" /> </element> </list> </class> </hibernate-mapping>
一、映射文件結構
Hibernate的持久化類和關系數據庫之間的映射通常是用一個XML文檔來定義的。該文檔通過一系列XML元素的配置,來將持久化類與數據庫表之間建立起一一映射。這意味着映射文檔是按照持久化類的定義來創建的,而不是表的定義。
1、根元素:<hibernate-mapping>,每一個hbm.xml文件都有唯一的一個根元素,包含一些可選的屬性
1)package:指定一個包前綴,如果在映射文檔中沒有指定全限定的類名,就使用這個作為包名,如
<hibernate-mapping package="com.demo.hibernate.beans">
<class name="User" ...>
< /hibernate-mapping>
< hibernate-mapping>
<class name="com.demo.hibernate.beans.User" ...>
< /hibernate-mapping>
2)schema:數據庫schema的名稱
3)catalog:數據庫catalog的名稱
4)default-cascade:默認的級聯風格,默認為none
5)default-access:Hibernate用來訪問屬性的策略
6)default-lazy:指定了未明確注明lazy屬性的Java屬性和集合類,Hibernate會采取什么樣的默認加載風格,默認為true
7)auto-import:指定我們是否可以在查詢語言中使用非全限定的類名,默認為true,如果項目中有兩個同名的持久化類,則最好在這兩個類的對應的映射文件中配置為false
2、<class>定義類:根元素的子元素,用以定義一個持久化類與數據表的映射關系,如下是該元素包含的一些可選的屬性
1)name:持久化類(或者接口)的Java全限定名,如果這個屬性不存在,則Hibernate將假定這是一個非POJO的實體映射
2)table:對應數據庫表名
3)discriminator-value:默認和類名一樣,一個用於區分不同的子類的值,在多態行為時使用
4)mutable:表明該類的實例是可變的或者是不可變的
5)schema:覆蓋根元素<hibernate-mapping>中指定的schema名字
6)catalog:覆蓋根元素<hibernate-mapping>中指定的catalog名字
7)proxy:指定一個接口,在延遲裝載時作為代理使用
8)dynamic-update:指定用於UPDATE的SQL將會在運行時動態生成,並且只更新那些改變過的字段
9)dynamic-insert:指定用於INSERT的SQL將會在執行時動態生成,並且只包含那些非空值字段
10)select-before-update:指定HIbernate除非確定對象真正被修改了(如果該值為true),否則不會執行SQL UPDATE操作。在特定場合(實際上,它只在一個瞬時對象關聯到一個新的Session中時執行的update()中生效),這說明Hibernate會在UPDATE之前執行一次額外的SQL SELECT操作,來決定是否應該執行UPDATE
11)polymorphism:多態,界定是隱式還是顯式的多態查詢
12)where:指定定個附加的SQLWHERE條件,在抓取這個類的對象時會增加這個條件
13)persister:指定一個定制的ClassPersister
14)batch-size:指定一個用於根據標識符(identifier)抓取實例時使用的'batch size'(批次抓取數量)
15)optimistic-lock:樂觀鎖定,決定樂觀鎖定的策略
16)lazy:通過設置lazy="false",所有的延遲加載(Lazy fetching)功能將未被激活(disabled)
17)entity-name
18)check:這是一個SQL表達式,用於為自動生成的schema添加多行(multi-row)約束檢查
19)rowid
20)subselect
21)abstract:用於在<union-subclass>的繼承結構(hierarchies)中標識抽象超類
二、映射主鍵
通常情況下,hibernate建議為持久化類定義一個標識屬性,用於唯一的標識某個持久化實例
標識屬性通過<id.../>元素來指定,<id.../>元素中的name屬性的值就是持久化類的標識屬性名,除此之外還可指定如下幾個屬性
1)type:標識Hibernate類型的名字
2)column:數據庫表的主鍵這段的名字
3)unsaved-value:用來標志該實例是剛剛創建的,尚未保存。可以用來區分對象的狀態
4)access:Hibernate用來訪問屬性值的策略
盡量避免使用復雜的物理主鍵,應該為數據庫增加一列,作為邏輯主鍵,hibernate為這種邏輯主鍵提供了主鍵生成器,用<generator>元素來指定主鍵的生成器
該元素的作用是指定主鍵的生成器,通過一個class屬性指定生成器對應的類。(通常與<id>元素結合使用)
<id name="id" column="ID" type="integer">
<generator class="native" />--native是Hibernate主鍵生成器的實現算法之一,由Hibernate根據底層數據庫自行判斷采用identity、hilo、sequence其中一種作為主鍵生成方式。
< /id>
Hibernate提供的內置生成器:
1)assigned算法
2)hilo算法
3)seqhilo算法
4)increment算法
5)identity算法
6)sequence算法
7)native算法
8)uuid.hex算法
9)uuid.string算法
10)foregin算法
11)select算法
三、映射普通屬性
普通屬性用<property>元素來表示持久化類的屬性與數據庫表字段之間的映射,包含如下屬性:
1)name:持久化類的屬性名,以小寫字母開頭
2)column:數據庫表的字段名
3)type:Hibernate映射類型的名字
4)update:表明用於UPDATE的SQL語句中是否包含這個被映射的字段,默認為true
5)insert:表明用於INSERT的SQL語句中是否包含這個被映射是否包含這個被映射的字段,默認為true
6)formula:一個SQL表達式,定義了這個計算屬性的值
7)access:Hibernate用來訪問屬性值的策略
8)lazy:指定實例變量第一次被訪問時,這個屬性是否延遲抓取,默認為false
9)unique:使用DDL為該字段添加唯一的約束,此外,這也可以用做property-ref的目標屬性
10)not-null:使用DDL為該字段添加可否為空的約束
11)optimistic-lock:指定這個屬性在進行更新時是否需要獲得樂觀鎖定(換句話說,它決定這個屬性發生臟數據時版本version的值是否增長)
access屬性用來讓你控制Hibernate如何在運行時訪問屬性。默認情況下,Hibernate會使用屬性的get/set方法對。如果你指明access="field",則Hibernate會忽略get/set方法對,直接使用反射來訪問成員變量。
formula屬性是個特別強大的的特征。用一個SQL表達式生成計算的結果,它會在這個實例轉載時翻譯成一個SQL查詢的SELECT子查詢語句。如:
<property name="totalPrice" formula="(SELECT SUM(*) FROM user)" />
如下面的實體類
- publicclass News
- {
- private Integer id;
- private String title;
- private String content;
- private String fullContent;
- //省略屬性的getter和setter方法
- }
public class News { private Integer id; private String title; private String content; private String fullContent; //省略屬性的getter和setter方法 }
對應的配置文件News.hbm.xml
- <?xmlversion="1.0"encoding="gb2312"?>
- <!-- 指定Hiberante3映射文件的DTD信息 -->
- <!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
- <!-- hibernate-mapping是映射文件的根元素 -->
- <hibernate-mappingpackage="org.crazyit.app.domain">
- <!-- 每個class元素對應一個持久化對象 -->
- <classname="News"table="news_table">
- <!-- id元素定義持久化類的標識屬性 -->
- <idname="id">
- <generatorclass="identity"/>
- </id>
- <!-- property元素定義常規屬性 -->
- <propertyname="title"not-null="true"/>
- <propertyname="content"/>
- <!-- 通過formula指定該屬性值沒有對應的實際數據列
- 該屬性值將由系統根據表達式來生成-->
- <propertyname="fullContent"
- formula="(select concat(nt.title,nt.content)
- from news_table nt where nt.id= id)"/>
- </class>
- </hibernate-mapping>
<?xml version="1.0" encoding="gb2312"?> <!-- 指定Hiberante3映射文件的DTD信息 --> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <!-- hibernate-mapping是映射文件的根元素 --> <hibernate-mapping package="org.crazyit.app.domain"> <!-- 每個class元素對應一個持久化對象 --> <class name="News" table="news_table"> <!-- id元素定義持久化類的標識屬性 --> <id name="id"> <generator class="identity"/> </id> <!-- property元素定義常規屬性 --> <property name="title" not-null="true"/> <property name="content"/> <!-- 通過formula指定該屬性值沒有對應的實際數據列 該屬性值將由系統根據表達式來生成--> <property name="fullContent" formula="(select concat(nt.title,nt.content) from news_table nt where nt.id= id)"/> </class> </hibernate-mapping>利用formula的強大特征,可以實現持久化類某個屬性的生成,而該屬性不會保存,不會有對應的數據列(即數據庫無此列數據,只包含在實體類里)
當保存News對象時
- News n = new News();
- n.setTitle("xxx");
- n.setContent("yyy");
- session.save(n);
News n = new News(); n.setTitle("xxx"); n.setContent("yyy"); session.save(n);
數據庫底層並無fullContent數據列,當再次取出News對象時,hibernate將執行formula配置的sql語句得出fullContent的屬性值
- News n2 = session.get(News.class,1)
- System.out.println(n2.getFullContent)
News n2 = session.get(News.class,1) System.out.println(n2.getFullContent)結果為"xxxyyy"
利用formula可以讓hibernate自動生成屬性的值,我們也可以由數據庫的觸發器來生成,不過數據庫必須增加fullContent數據列,
只要將
- <propertyname="fullContent"
- formula="(select concat(nt.title,nt.content)
- from news_table nt where nt.id= id)"/>
<property name="fullContent" formula="(select concat(nt.title,nt.content) from news_table nt where nt.id= id)"/>改為
- <propertyname="fullContent"generated="insert"/>
<property name="fullContent" generated="insert"/>hibernate將會讓數據庫執行insert類型觸發器(什么,觸發器怎么寫?自己google去)
四、映射集合、組件。。。屬性
Hibernate要求持久化集合值字段必須聲明為接口,可以是java.util.Set、java.util.Collection、java.util.List、java.util.Map、java.util.SortedSet、java.util.SortedMap等
對於hibernate中,集合屬性在Hibernate的映射文件中是非常常見的,也是非常重要的內容,理解和熟練掌握常用的集合屬性則顯得更為重要。在hibernate的配置文件中,例如每個人的考試成績,就是典型的Map結構,每門功課對應一門成績。或者更簡單的集合屬性,某個企業的部門,一個企業通常對應多個部門等。集合屬性是現實生活中非常普遍的屬性關系。集合屬性大致有兩種:第一種是單純的集合屬性,例如像List,Set或數組等集合屬性;還有一種就是Map結構的集合屬性。每個屬性都有對應的key映射.基本配置如下
- <hibernate-mapping>
- <classname="zyw.app.domain.Person1">
- <idname="id"type="java.lang.Integer">
- <generatorclass="identity"/>
- </id>
- <propertyname="name"type="java.lang.String"/>
- <propertyname="age"type="java.lang.Integer"/>
- <listname="schools"inverse="false"table="school"lazy="true">
- <key>
- <columnname="person_id"/>
- </key>
- <list-indexcolumn="schools_order"/>
- <elementtype="java.lang.String">
- <columnname="school_name"/>
- </element>
- </list>
- </class>
- </hibernate-mapping>
<hibernate-mapping> <class name="zyw.app.domain.Person1"> <id name="id" type="java.lang.Integer"> <generator class="identity" /> </id> <property name="name" type="java.lang.String"/> <property name="age" type="java.lang.Integer"/> <list name="schools" inverse="false" table="school" lazy="true"> <key> <column name="person_id" /> </key> <list-index column="schools_order"/> <element type="java.lang.String"> <column name="school_name" /> </element> </list> </class> </hibernate-mapping>
添加集合屬性元素配置步驟如下:
1、集合屬性的元素大致有如下幾種: (1)<set../>元素:可以映射類型為java.util.Set接口的屬性,它的元素存放沒有順序且不允許重復,也可以映射類型為java.util.SortSet接口的屬性,它的元素可以按自然屬性排序,也可以用sort屬性指定排序規則
(2)<list.../>元素:可以映射類型為java.util.List接口的屬性,它需要在結合屬性對象的數據庫表中用一個額外的索引列保存每一個元素的位置,即是有屬性可重復的。
(3)<bag.../>元素:可以映射java.util.Collection接口的屬性,它的元素可能重復,但不保存屬性,和set差不多,正因為有它,是因為如果通常使用list比較多,並且不想讓添加一列的話,就用它。
(4)<map.../>元素:可以映射為java.util.Map接口的屬性,它的元素以鍵值對的形式保存,也是無序的,也可以映射類型為java.util.SortMap接口的屬性,它的元素可以按自然順序排序,也可以用sort屬性指定排序規則
(5)<array.../>元素:可以映射類型為數組的屬性,但在實際運用中用的極少
(6)<primitive-array.../>元素:可以映射類型為基本數據類型數組的屬性,但在實際運用中用的極少
2、因為集合屬性都需要保存到另一個數據表中,所以保存集合屬性的數據表必須包含一個外鍵列用於參照到主鍵列,可以在集合屬性元素中用子元素<key.../>來映射
<key.../>元素有如下屬性
column:指定外鍵字段的列名
on-delete:是否打開級聯刪除
property-ref:指定外鍵字段是否為原表的主鍵
not-null:非空約束
update:是否可更新
unique:是否唯一約束
2、除了<set.../>和<bag.../>元素外,都要為集合元素的數據表指定一個索引列——用於保存數組索引,List索引,或者Map集合的key索引,在集合屬性元素中用於映射索引列的子元素有如下幾個
<List-index/>用於List,數組
<map-key/>用於映射Map,基本數據類型的索引列
<map-key-many-to-many/>用於Map中實體類型的引用(即key為實體類)
<composite-map-key/>用於Map中復合類型的引用(即key為組件,非實體類,就是一個復合類型類)
3、最后,我們還需要映射集合元素的值屬性
<element.../>集合元素是基本類型或包裝類,字符串類型,日期類型
<composite-element.../>集合元素是復合類型的引用(即key為組件,非實體類,就是一個復合類型類)
<one-to-many.../>或<many-to-many.../>集合元素是實體類型的引用(即key為實體類)
記憶規則其實很簡單,可以這么記:
基本配置:
- <hibernate-mapping>
- <classname="zyw.app.domain.Person1">
- <idname="id">
- <generatorclass="identity"/>
- </id>
- <propertyname="name"/>
- <propertyname="age"/>
- </class>
- </hibernate-mapping>
<hibernate-mapping> <class name="zyw.app.domain.Person1"> <id name="id"> <generator class="identity" /> </id> <property name="name"/> <property name="age"/> </class> </hibernate-mapping>A.如果<property/>屬性為集合屬性,按照123步驟置換成對應的元素即可,如schools為一個list屬性
- <listname="schools"inverse="false"table="school"lazy="true">
- <key>
- <columnname="person_id"/>
- </key>
- <list-indexcolumn="schools_order"/>
- <elementtype="java.lang.String">
- <columnname="school_name"/>
- </element>
- </list>
<list name="schools" inverse="false" table="school" lazy="true"> <key> <column name="person_id" /> </key> <list-index column="schools_order"/> <element type="java.lang.String"> <column name="school_name" /> </element> </list>B.如果 <property/>屬性為組件屬性,如Name類(Name是一個自定義類,含有first和last兩個屬性),置換成<component.../>元素,要指定自定義類的路徑
- <componentname="name"class="<span style="color: rgb(255, 0, 0);">zyw.app.componet.Name</span>">
- <propertyname="first"column="FIRST"></property>
- <propertyname="last"column="LAST"></property>
- </component>
<component name="name" class="zyw.app.componet.Name"> <property name="first" column="FIRST"></property> <property name="last" column="LAST"></property> </component>
同理
如果組件屬性里還有集合屬性,繼續A置換
如果組件屬性里還有組件屬性,繼續B置換,<component.../>變成<nested-composite-element.../>
如果集合Map的索引屬性為組件屬性,繼續B置換,<component.../>變成<nested-composite-element.../>,子元素為<key-property.../>或<key-many-to-one.../>
C。如果<id.../>為組件屬性,組件類必須重寫過equals和hashCode方法,<id.../>元素置換為
- <composite-idname="xxx"class="xxx.xxx.xxx">
- <key-propertyname="xxx"/>
- <key-propertyname="xxx"/>
- </composite-id>
<composite-id name="xxx" class="xxx.xxx.xxx"> <key-property name="xxx"/> <key-property name="xxx"/> </composite-id>或者多列為聯合主鍵,省去name和class屬性即可,效果一樣
- <composite-id>
- <key-propertyname="xxx"/>
- <key-propertyname="xxx"/>
- </composite-id>
<composite-id> <key-property name="xxx"/> <key-property name="xxx"/> </composite-id>
五、JPAAnnotation標注實體
不多說,給一份大概配置了解一下
- <preclass="java"name="code">@Entity
- @Table(name="person_table")
- public class Person
- {
- /* 指定使用復合主鍵類是Name */
- @EmbeddedId
- @AttributeOverrides({
- @AttributeOverride(name="first"
- , column=@Column(name="person_first")),
- @AttributeOverride(name="last"
- , column=@Column(name="person_last" , length=20))
- })
- private Name name;
- //普通屬性
- @Column(name="person_email")
- private String email;
- @Embedded
- @AttributeOverrides({
- @AttributeOverride(name="name"
- , column=@Column(name="cat_name" , length=35)),
- @AttributeOverride(name="color"
- , column=@Column(name="cat_color"))
- })
- //組件屬性,代表此人擁有的寵物
- private Cat pet;
- //name屬性的setter和getter方法
- public void setName(Name name)
- {
- this.name = name;
- }
- public Name getName()
- {
- return this.name;
- }
- //email屬性的setter和getter方法
- public void setEmail(String email)
- {
- this.email = email;
- }
- public String getEmail()
- {
- return this.email;
- }
- //pet屬性的setter和getter方法
- public void setPet(Cat pet)
- {
- this.pet = pet;
- }
- public Cat getPet()
- {
- return this.pet;
- }
- }</pre><br>
- <br>
- <pre></pre>
- <preclass="html"name="code"></pre>
- <br>