hibernate 集合类(Collections)映射
?Hibernate可以持久化以下java集合的實例, 包括java.util.Map, java.util.Set, java.util.SortedMap, java.util.SortedSet, java.util.List, 和任何持久實體或值的數組(使用Set集合類型是最好的選擇)。類型為java.util.Collection或者java.util.List的屬性還可以使用"bag"語義來持久。用于持久化的集合,除了集合接口外,不能保留任何實現這些接口的類所附加的語義(例如:LinkedHashSet帶來的迭代順序)。所有的持久化集合,實際上都各自按照 HashMap, HashSet, TreeMap, TreeSet 和 ArrayList 的語義直接工作。更深入地說,對于一個包含集合的屬性來說,必須把Java類型定義為接口(也就是Map, Set 或者List等),而絕不能是HashMap, TreeSet 或者 ArrayList。存在這個限制的原因是,在你不知道的時候,Hibernate暗中把你的Map, Set 和 List 的實例替換成了它自己的關于Map, Set 或者 List 的實現。(所以在你的程序中,謹慎使用==操作符。)(說明: 為了提高性能等方面的原因,在Hibernate中實現了幾乎所有的Java集合的接口(為了實現懶加載的一些特性) 。)所有的有序集合類(maps, lists, arrays)都擁有一個由<key>和 <index>組成的主鍵。 這種情況下集合類的更新是非常高效的——主鍵已經被有效的索引,因此當Hibernate試圖更新或刪除一行時,可以迅速找到該行數據。集合(sets)的主鍵由<key>和其他元素字段構成。 對于有些元素類型來說,這很低效,特別是組合元素或者大文本、大二進制字段; 數據庫可能無法有效的對復雜的主鍵進行索引。 另一方面,對于一對多、多對多關聯,特別是合成的標識符來說,集合也可以達到同樣的高效性能。( 附注:如果你希望SchemaExport為你的<set>創建主鍵, 你必須把所有的字段都聲明為not-null="true"。)<idbag>映射定義了代理鍵,因此它總是可以很高效的被更新。事實上, <idbag>擁有著最好的性能表現。Bag是最差的。因為bag允許重復的元素值,也沒有索引字段,因此不可能定義主鍵。 Hibernate無法判斷出重復的行。當這種集合被更改時,Hibernate將會先完整地移除 (通過一個(in a single DELETE))整個集合,然后再重新創建整個集合。 因此Bag是非常低效的。
?一、Set集合映射
我的前幾篇文章,many-to-many, many-to-one中都用的是Set集合映射,在此不再累述。
?當實體類中有HashSet屬性時,它是如何進行初始化的呢?當持久化這個實體類的一個實例,比如調用persist()方法進行了持久化時,hibernate將自動利用hibernate自己實現了Set接口的類替換掉HashSet。所以一定要防止出現如下所示的錯誤:
Java代碼 ??當運行時,會出現如下的異常:
java.lang.ClassCastException: org.hibernate.collection.PersistentSet cannot be cast to java.util.HashSet
二、List集合映射
1. 實體類:
實體類還是采用Department和Employee,詳見我寫的多對一(many-to-one)文章,在它們的基礎上進行修改如下所示:
將原Department實體類中的Set替換成List,如下所示:
Java代碼 ?在原Employee實體類中增加了重寫的toString()方法,方法如下:
Java代碼 ??2. 配置文件:
修改Department.hbm.xml配置文件,其它的還是保持以前的不變,修改的Department.hbm.xml配置文件如下:
Xml代碼 ??3.測試類(只是對many-to-one中的測試類進行了少量的修改),如下所示:
Java代碼 ??執行測試類,控制臺打印如下信息:
emps:[id=1 name=employee1 name1, id=2 name=employee2 name2]
將測試類中注釋為1和注釋為2的語句對換順序后,重新執行,控制臺打印如下信息:
emps:[id=2 name=employee2 name2, id=1 name=employee1 name1]
再看數據庫表中的記錄,如下所示:
mysql> select * from department;
+----+-----------------+
| id | name??????????? |
+----+-----------------+
|? 1 | department name |
+----+-----------------+
1 row in set (0.00 sec)
mysql> select * from employee;
+----+-----------------+-----------+-----------+
| id | name??????????? | depart_id | order_col |
+----+-----------------+-----------+-----------+
|? 1 | employee1 name1 |???????? 1 |???????? 1 |
|? 2 | employee2 name2 |???????? 1 |???????? 0 |
+----+-----------------+-----------+-----------+
2 rows in set (0.00 sec)
說明使用List時,因為配置文件下增加了<list-index column="order_col" />對加入List集合的元素的順序進行記錄,測試結果表明,確實對加入順序進行了記錄。
?
三、bag集合映射(使用bag集合映射時,注意實體類中還是使用java.util.List與之對應)
?? 如果在實體類中使用了List類型的屬性,而我們并不希望保證集合中元素的順序(保證集合中元素的順序會采用排序算法,因而會占用一些CPU資源,一定程序上影響性能),可以在配置文件中使用<bag>,它的使用與<list>唯一不同的就是不保證集合中元素的順序。
在List集合映射的基礎上,只需將配置文件中list部分替換成bag即可,其余部分不用修改,Department.hbm.xml配置文件修改如下:
Java代碼 ?將測試類中注釋為1和注釋為2的語句對換順序后執行,控制臺打印如下信息:
emps:[id=1 name=employee1 name1, id=2 name=employee2 name2]
說明已經不再保證它的元素加入的順序了。
再看數據庫表中的記錄,如下所示:
?mysql> select * from department;
+----+-----------------+
| id | name??????????? |
+----+-----------------+
|? 1 | department name |
+----+-----------------+
1 row in set (0.00 sec)
mysql> select * from employee;
+----+-----------------+-----------+
| id | name??????????? | depart_id |
+----+-----------------+-----------+
|? 1 | employee1 name1 |???????? 1 |
|? 2 | employee2 name2 |???????? 1 |
+----+-----------------+-----------+
2 rows in set (0.00 sec)
此時數據庫就少了記錄順序的那一列值了。
?
四、Map集合映射
Map集合屬性不僅需要映射屬性value,還需要映射屬性key。這里假設Employee的name屬性是唯一的,如下修改Employee.hbm.xml配置文件中的name屬性,設置unique='true':
Java代碼 ??實體類Department如下:
Java代碼 ??修改Department.hbm.xml配置文件如下:
Xml代碼 ??將測試類下如下注釋部分(即List部分)替換,改成Map重新進行測試:
Java代碼 ??測試結果如下:
emps:{employee1 name1=id=1 name=employee1 name1, employee2 name2=id=2 name=employee2 name2}(紅色標記部分為key部分)
數據庫表中記錄如下所示(未發生變化):
mysql> select * from department;
+----+-----------------+
| id | name??????????? |
+----+-----------------+
|? 1 | department name |
+----+-----------------+
1 row in set (0.00 sec)
mysql> select * from employee;
+----+-----------------+-----------+
| id | name??????????? | depart_id |
+----+-----------------+-----------+
|? 1 | employee1 name1 |???????? 1 |
|? 2 | employee2 name2 |???????? 1 |
+----+-----------------+-----------+
2 rows in set (0.00 sec)
五、array(數組)映射
將實體類Department修改如下:
Java代碼 ??Department.hbm.xml修改如下:
Java代碼 ??測試類修改如下:
Java代碼 ??測試結果如下所示,控制臺打印結果:
id=2 name=employee2 name2
id=1 name=employee1 name1
數據庫表中記錄:
mysql> select * from department;
+----+-----------------+
| id | name??????????? |
+----+-----------------+
|? 1 | department name |
+----+-----------------+
1 row in set (0.00 sec)
mysql> select * from employee;
+----+-----------------+-----------+-----------+
| id | name??????????? | depart_id | order_col |
+----+-----------------+-----------+-----------+
|? 1 | employee1 name1 |???????? 1 |???????? 1 |
|? 2 | employee2 name2 |???????? 1 |???????? 0 |
+----+-----------------+-----------+-----------+
2 rows in set (0.00 sec)
總結:
集合映射(set,list,array,bag,map)這些集合類都是Hibernate實現的類和JAVA中的集合不完全一樣,set,list,map
分別和JAVA中的Set,List,Map接口對應,bag映射成JAVA的List;這些集合的使用和JAVA集合中對應的接口基本一致;在JAVA的實體類中集合只能定義成接口,不能定義成具體類,因為集合會在運行時被替換成Hibernate的實現。除了Set和Bag之外的所有集合類型都有一個索引(index)字段,這個字段映射到一個數組或者List的索引或者Map的key。Map的索引的類型可以是任何基本類型, 實體類型或者甚至是一個組合類型(但不能是一個集合類型)。數組和list的索引肯定是整型,integer。在Hibernate配置文件中使用 <index>, <index-many-to-many>, <composite-index> 或者<index-many-to-any>等元素來映射索引。集合的簡單使用原則:大部分情況下用set,需要保證集合中的順序時用list,想用java.util.List又不需要保證順序時用bag.
總結
以上是生活随笔為你收集整理的hibernate 集合类(Collections)映射的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hibernate 继承映射
- 下一篇: Hibernate4一对多关系映射(自身