Hibernate联合主键映射
1. 实现方式一:将复合主键对应的属性与实体其他普通属性放在一起
2. 实现方式二:将主键属性提取到一个主键类中,实体类只需包含主键类的一个引用
联合主键的映射规则
1) 类中的每个主键属性都对应到数据表中的每个主键列。
Hibernate要求具有联合主键的实体类实现Serializable接口,并且重写hashCode与equals方法。
1. 使用复合主键的实体类必须实现Serializable接口。必须实现Serializable接口的原因很简单,我们查找数据的时候是根据主键查找的。打开Hibernate的帮助文档我们可以找到get与load方法的声明形式如下:
Object load(Class theClass,Serializable id)
Object get(Class theClass,Serializable id)
当我们查找复合主键类的对象时,需要传递主键值给get()或load()方法的id参数,而id参数只能接收一个实现了Serializable接口的对象。而复合主键类的主键不是一个属性可以表示的,所以只能先new出复合主键类的实例(例如:new People()),然后使用主键属性的set方法将主键值赋值给主键属性,然后将整个对象传递给get()或load()方法的id参数,实现主键值的传递,所以复合主键的实体类必须实现Serializable接口。
应用场景:
主键类为什么要序列化?如果多个该类对象同时放入内存中,在一个集群系统中,其中一台服务器当机了,需要将内存中对象写到其它服务器。同时,如果该服务器内存以满,需要用虚拟内存,这就需要序列化后才能写到硬盘上。
2. 使用复合主键的实体类必须重写equals和hashCode方法。必须重写equals和hashCode方法也很好理解。这两个方法使用于判断两个对象(两条记录)是否相等的。为什么要判断两个对象是否相等呢?因为数据库中的任意两条记录中的主键值是不能相同的,所以我们在程序中只要确保了两个对象的主键值不同就可以防止主键约束违例的错误出现(程序中要确保对象的唯一性需要重写hashCode()和equal()方法)。也许这里你会奇怪为什么不使用复合主键的实体类不重写这两个方法也没有主键违例的情况出现,这是因为使用单一主键方式,主键值是Hibernate来维护的,它会确保主键不会重复,而复合主键方式,主键值是编程人员自己维护的,所以必须重写equals和hashCode方法用于判断两个对象的主键是否相同。
3. 重写的equals和hashCode方法,只与主键属性有关,普通属性不要影响这两个方法进行判断。这个原因很简单,主键才能决定一条记录,其他属性不能决定一条记录。
2) 将主键所对应属性提取出一个类(称之为主键类),并且主键类需要实现Serializable接口,重写equals方法与hashCode方法,原因与上面一样。
方式一:将复合主键对应的属性与实体其他普通属性放在一起
例如实体类People中"id"和"name"属性对应复合主键:
Java代码
1. public class People implements Serializable {
2. private static final long serialVersionUID = -4888836126783955019L;
3. private String id;
4. private String name;
5. private int age;
6.
7. public People() {
8. }
9.
10. public String getId() {
11. return id;
12. }
13.
14. public void setId(String id) {
15. this.id = id;
16. }
17.
18. public String getName() {
19. return name;
20. }
21.
22. public void setName(String name) {
23. this.name = name;
24. }
25.
26. public int getAge() {
27. return age;
28. }
29.
30. public void setAge(int age) {
31. this.age = age;
32. }
33.
34. @Override
35. public int hashCode() {
36. final int prime = 31;
37. int result = 1;
38. result = prime * result + ((id == null) ? 0 : id.hashCode());
39. result = prime * result + ((name == null) ? 0 : name.hashCode());
40. return result;
41. }
42.
43. @Override
44. public boolean equals(Object obj) {
45. if (this == obj)
46. return true;
47. if (obj == null)
48. return false;
49. if (getClass() != obj.getClass())
50. return false;
51. People other = (People) obj;
52. if (id == null) {
53. if (other.id != null)
54. return false;
55. } else if (!id.equals(other.id))
56. return false;
57. if (name == null) {
58. if (other.name != null)
59. return false;
60. } else if (!name.equals(other.name))
61. return false;
62. return true;
63. }
64.}
=======People.hbm.xml:
Xml代码
1. <?xml version="1.0" encoding="utf-8"?>
2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
3. <hibernate-mapping>
4. <class name="com.suxiaolei.hibernate.pojos.People" table="people">
5. <!-- 复合主键使用composite-id标签 -->
6. <composite-id>
7. <!-- key-property标签表示哪一些属性对应复合主键 -->
8. <key-property name="id" column="id" type="string">
9. </key-property>
10.<key-property name="name" column="name" type="string">
11.</key-property>
12.</composite-id>
13.<property name="age" column="age" type="integer">
14.</property>
15.</class>
16.</hibernate-mapping>
方式二:将主键属性提取到一个主键类中,实体类只需包含主键类的一个引用
主键类:
======PeoplePrimaryKey.java
Java代码
1. import java.io.Serializable;
2.
3. /*必须实现Serializable接口*/
4. public class PeoplePrimaryKey implements Serializable {
5. private static final long serialVersionUID = -1190986010439330142L; /* 复合主键值 */
6. private String id;
7. private String name;
8.
9. public PeoplePrimaryKey() {
10. } /* 复合主键值的get和set方法 */
11.
12. public String getId() {
13. return id;
14. }
15.
16. public void setId(String id) {
17. this.id = id;
18. }
19.
20. public String getName() {
21. return name;
22. }
23.
24. public void setName(String name) {
25. this.name = name;
26. }
27.
28. @Override
29. public int hashCode() {
30. final int prime = 31;
31. int result = 1;
32. result = prime * result + ((id == null) ? 0 : id.hashCode());
33. result = prime * result + ((name == null) ? 0 : name.hashCode());
34. return result;
35. }
36.
37. @Override
38. public boolean equals(Object obj) {
39. if (this == obj)
40. return true;
41. if (obj == null)
42. return false;
43. if (getClass() != obj.getClass())
44. return false;
45. PeoplePrimaryKey other = (PeoplePrimaryKey) obj;
46. if (id == null) {
47. if (other.id != null)
48. return false;
49. } else if (!id.equals(other.id))
50. return false;
51. if (name == null) {
52. if (other.name != null)
53. return false;
54. } else if (!name.equals(other.name))
55. return false;
56. return true;
57. }
58.}
===People.java
Java代码
1. public class People { /* 持有主键类的一个引用,使用该引用作为这个类的OID */
2. private PeoplePrimaryKey peoplePrimaryKey;
3. private int age;
4.
5. public People() {
6. }
7.
8. public PeoplePrimaryKey getPeoplePrimaryKey() {
9. return peoplePrimaryKey;
10. }
11.
12. public void setPeoplePrimaryKey(PeoplePrimaryKey peoplePrimaryKey) {
13. this.peoplePrimaryKey = peoplePrimaryKey;
14. }
15.
16. public int getAge() {
17. return age;
18. }
19.
20. public void setAge(int age) {
21. this.age = age;
22. }
23.}
===People.hbm.xml文件稍有一点变动:
Java代码
1. <?xml version="1.0" encoding="utf-8"?>
2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
3. <hibernate-mapping>
4. <class name="com.suxiaolei.hibernate.pojos.People" table="people">
5. <!-- 复合主键使用composite-id标签 -->
6. <!--name - 指定了复合主键对应哪一个属性class - 指定了复合主键属性的类型-->
7. <composite-id name="peoplePrimaryKey" class="com.suxiaolei.hibernate.pojos.PeoplePrimaryKey">
8. <!-- key-property指定了复合主键由哪些属性组成 -->
9. <key-property name="id" column="id" type="string">
10.</key-property>
11.<key-property name="name" column="name" type="string">
12.</key-property>
13.</composite-id>
14.<property name="age" column="age" type="integer">
15.</property>
16.</class>
17.</hibernate-mapping>