一、簡述 1.對象關係映射文件,用於映射實體類和關係資料庫數據表之間的一個 xml 文件。 2.通過 Entity.hbm.xml 映射文件,Hibernate 可以理解持久化類和數據表之間的對應關係,也可以理解持久化類屬性與數據表列之間的對應關係。 3.映射主鍵、映射關聯關係。 二、各個節點 說明 ...
一、簡述
1.對象關係映射文件,用於映射實體類和關係資料庫數據表之間的一個 xml 文件。
2.通過 Entity.hbm.xml 映射文件,Hibernate 可以理解持久化類和數據表之間的對應關係,也可以理解持久化類屬性與數據表列之間的對應關係。
3.映射主鍵、映射關聯關係。
二、各個節點
<hibernate-mapping> <class> <id></id> <property name=""></property> <many-to-one name=""></many-to-one> <one-to-one name=""></one-to-one> <set name=""> <key></key> <one-to-many></one-to-many> <many-to-many></many-to-many> </set> <subclass></subclass> <joined-subclass> <key></key> </joined-subclass> <component name=""></component> <any id-type="" name=""> <column name=""></column> <column name=""></column> </any> </class> </hibernate-mapping>
說明:在一個 Entity.hbm.xml 可以定義多個 class 節點,但是通常情況下只定義一個。
1.<hibernate-mapping>
(1)package
如果 hibernate-mapping 節點記憶體在多個 class 節點,可以通過這個屬性來簡化開發。相當於一個命名空間。
單個 class 節點的情況下:
<hibernate-mapping > <class name="com.nucsoft.hibernate.News" table="news" schema="hibernate"> </class> </hibernate-mapping>
多個 class 節點的情況下:
<hibernate-mapping package="com.nucsoft.hibernate"> <class name="News" table="news" schema="hibernate"> </class> <class name="Users" table="users" schema="hibernate"> </class> </hibernate-mapping>
2.<class>
(1)name:類名,如 com.nucsoft.hibernate.News。
(2)table:表明,如 news。類名和表名不一定一致。
(3)schema:庫名。如 hibernate 。
(4)dynamic-insert:動態插入。預設為 false。若設置為 true,表示當插入一個對象時,會動態生成 insert 語句,insert 語句僅包含所有取值不為 null 的欄位。
①預設
@Test public void testDynamicInsert() { News news = new News("bb", null, new java.util.Date()); session.save(news); }
控制台列印:
Hibernate:
insert
into
hibernate.news
(title, author, date)
values
(?, ?, ?)
②設置 dynamic-insert="true"
@Test public void testDynamicInsert() { News news = new News("cc", null, new java.util.Date()); session.save(news); }
控制台列印:
Hibernate:
insert
into
hibernate.news
(title, date)
values
(?, ?)
註意:設置為 null 的欄位不存在 非空約束。
(5)dynamic-update:動態更新。預設為 false。若設置為 true,表示當更新一個對象時,會動態生成 update 語句,update 語句中僅包含所有取值需要更新的欄位。
①預設
@Test public void testDynamicUpdate() { News news = (News) session.get(News.class, 205); news.setAuthor("BB"); }
控制台列印:
Hibernate: update hibernate.news set title=?, author=?, date=? where id=?
②設置 dynamic-update="true"
@Test public void testDynamicUpdate() { News news = (News) session.get(News.class, 206); news.setAuthor("CC"); }
控制台列印:
Hibernate: update hibernate.news set author=? where id=?
(6)select-before-update:設置某個持久化對象在更新前是否執行一次查詢。如,對一個游離對象的更新,再更新前先查詢使游離對象變為持久化對象,
若該對象和資料庫中對應記錄狀態一致,則不再發送 UPDATE 語句。但是會影響性能。
3.<id>
說明:
- Hibernate 通過 OID 來建立記憶體中的對象和數據表中記錄的對應關係。對象的 OID 和數據表的主鍵對應。Hibernate 通過標識符生成器來為主鍵賦值。
- Hibernate 推薦在數據表中使用代理主鍵,即不具備任何業務含義的欄位。代理主鍵通常為整型。
- <id> 節點用來設置對象標識符,<generator> 子元素用來設定標識符生成器。Hibernate 提供了標識符生成器介面:IdentifierGenerator,提供了內置的實現,我們也可以通過實現這個介面來定義我們自己的生成器。
(1)name:持久化類的屬性名。
(2)column:對應數據表的列名。
(3)type:Hibernate 的映射類型。
(4)unsaved-value:如果存在一個對象的 id 和 unsaved-value 值相同,會被認為成一個臨時對象。
(4)子節點:<generator>。為持久化類設定標識符生成器。
- class 屬性,生成器的全限定類名或縮寫。一般使用縮寫。
- increment:會存在併發問題,會出現主鍵重覆。只適用於測試。
- hilo:在Hibernate 4.2.2 版本中,已過時。org.hibernate.id.enhanced.SequenceStyleGenerator 替代了它。
4.<property>
(1)name:指定該持久化類的屬性名稱。
(2)type:Hibernate 映射類型。(Hibernate 映射類型,是 Java 類型和 SQL 類型的橋梁)
(3)column:指定映射的表的欄位名,可以定義為子節點的形式。
(4)access:指定 Hibernate 的預設的屬性訪問策略。預設為 property,即使用 getter/setter。若指定 field,則通過反射來訪問成員變數。
(5)unique:是否添加一個唯一約束。
(6)update:這一列的值是否可以被修改。
(7)index:指定一個索引名稱。
(8)scale:指定該屬性所映射數據列的小數位。對 double/float/decimal 等有效。
(9)formula:設置一個 Sql 表達式,Hibernate 將根據它來計算出派生屬性的值。
註意:
- 派生屬性:並不是持久化類的所有屬性都直接和表的欄位匹配,持久化類的有些屬性的值必須在運行時才能計算出來。
- formula="(sql)" 括弧不能少。
- sql 語句中的列名和表名應與資料庫中的列名和表名對應,而不是和持久化類名和屬性名對應。
e:在 News 中添加了 String 類型的 desc 欄位。
News.hbm.xml 配置:
<property name="desc" formula="(SELECT concat(title, ': ', author) FROM news n WHERE n.id = id)"/>
測試:
@Test public void testFormula() { News news = (News) session.get(News.class, 1); System.out.println(news.getDesc()); }
控制台列印:
Hibernate: select news0_.id as id1_0_0_, news0_.title as title2_0_0_, news0_.author as author3_0_0_, news0_.date as date4_0_0_, (SELECT concat(news0_.title, ': ', news0_.author) FROM news n WHERE n.id = news0_.id) as formula0_0_ from hibernate.news news0_ where news0_.id=? dd: DD
可以發現,是以子查詢的方式來設置派生屬性的。
三、映射時間、日期類型
1.基礎知識
(1)在 Java 中,代表日期和時間的類型有:java.util.Date 和 java.util.Calendar。此外,JDBC 提供了 3 個擴展:java.sql.Date、java.sql.Time、java.sql.Timestamp。
分別和標準 SQL 的 date 、time、timestamp 類型對應。
(2)在標準 SQL 中,DATE 類型表示日期,TIME 類型表示時間,TIMESTAMP 類型表示時間戳,同時包含日期和時間信息。
(3)因為 java.util.Date 是 java.sql.Date,java.sql.Time 和 java.sql.Timestamp 的父類,所以 java.util.Date 可以對應標準 SQL 的Date、Time、Timestamp 類型。
基於上述所說,可以將實體類的 Date 類型設置為 java.util.Date 類型。
(4)如何將 java.util.Date 映射為 Date,Time,Timestamp?
①在 Eclipse 下,是根據實體和映射文件去生成數據表。
可以通過 property 的 type 屬性來進行映射。
例如:
<property name="date" type="timestamp"> <column name="DATE" /> </property> <property name="date" type="data"> <column name="DATE" /> </property> <property name="date" type="time"> <column name="DATE" /> </property>
其中 timestamp, date, time 既不是 Java 類型, 也不是標準 SQL 類型, 而是 hibernate 映射類型。
②在 Intellij Idea 下,是根據表去生成 Entity.hbm.xml 和實體類。
生成的實體日期類型為具體的 java.sql.date 或 java.sql.time 或 java.sql.timestamp。
這裡需要對其更改為其父類:java.util.date。
經過測試發現,對應 property 的 type 屬性寫與不寫都不會影響最終結果。如:
<property name="birthday"> <column name="birthday" sql-type="timestamp"/> </property>
插入的結果也是帶有日期和時間的時間戳。
③小結:在 Eclipse 下,必須要顯式的指定 property 的 type 屬性,來進行日期時間的精確映射。而在 Intellij Idea 下,需要將實體類的日期和時間類型改為 java.util.Date 類型。
(5)Java 類型、Hibernate 類型、標準 SQL 類型對應表
四、關於 Blob,Clob 這裡不進行說明。在項目中處理二進位和大數據類型的對象很少通過 Blob和 Clob進行存儲。
五、總結
介紹了實體類和數據表是如何映射的,主鍵是怎麼生成的,是怎麼映射的,屬性和列是怎麼映射的。也介紹了日期時間的映射。