上一篇博客简单介绍了SpringData JPA实现简单的CRUD,分页与多条件的排序,那里的主键类型是Long,有时我们会遇到主键不是一个的,复合主键,经过调研如下。确定一个人,不能只根据他的姓名来确定,因为会有重名,现在我们假设姓名、身份证号确定唯一一个人。
复合主键:一张表存在多个字段共同组成一个主键,这多个字段的组合不能重复,但是单独一个可以重复。
例子:姓名和省份证号共同组成了主键

二、采用@IdClass来注解复合主键
过程和@Embeddable差不多,这里直接贴例子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | @Entity @Table (name = "people" ) @IdClass (PeopleKey. class ) public class People implements Serializable { // @EmbeddedId // private PeopleKey id; @Id @Column (name = "name" ) private String name; @Id @Column (name = "idcardno" ) private String idcardno; @Column (name = "age" ) private int age; @Column (name = "address" ) private String address; } |
1 2 3 4 5 6 7 8 9 | public class PeopleKey implements Serializable { // @Id // @Column(name = "name") private String name; // @Id // @Column(name = "idcardno") private String idcardno; } |
采用这个方法的我参考博客里有一篇,写的比较详细,但是感觉这个方法不好,本身就已经在PeopleKey中把主键给封装了,但是在实体类People中还要把复合主键给加入进去,不够简介,采用第一种方法,就很简单,而且也体现了Java类封装的思想。
一、Spring Data Jpa 复合主键
1.1、编写一个复合主键类:PeopleKey
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @Embeddable public class PeopleKey implements Serializable { @Column (name = "name" ) private String name; @Column (name = "idcardno" ) private String idcardno; // 省略setter,getter方法 @Override public String toString() { return "PeopleKey [name=" + name + ", idcardno=" + idcardno + "]" ; } } |
注意:
1) 实现Serializable
接口(否则会报错,错误会直接显示);
2)在复合主键的类上,使用注解@Embeddable
3) 有默认的public无参数的构造方法(在我这个实例中,我没有添加有参构造方法,所以采用默认的构造方法)
如果你在实体类里有有参构造方法,那么一定要有一个无参构造方法,否则运行的时候会报错
1 | org.hibernate.InstantiationException: No default constructor for entity: : com.my.model.People |
这个就是没有默认的构造方法造成的,所以要在实体类中加入默认的无参构造方法。
4) 重写equals
和hashCode
方法。equals方法用于判断两个对象是否相同,EntityManger通过find方法来查找Entity时,是根据equals的返回值来判断的。hashCode方法返回当前对象的哈希码(我验证EntityManger,不重写也没事。);
1.2、编写实体类:People
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package com.my.model; import javax.persistence.*; @Entity @Table (name = "people" ) //@IdClass(PeopleKey.class) public class People extends PeopleKey{ // 复合主键要用这个注解 @EmbeddedId private PeopleKey id; @Column (name = "age" ) private int age; @Column (name = "address" ) private String address; // 省略setter,getter方法 @Override public String toString() { return "People [id=" + id + ", age=" + age + ", address=" + address + "]" ; } } |
1.3 测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @Service public class PeopleService { @Resource private PeopleRepository peopleRepository; public People findOne() { PeopleKey peopleKey = new PeopleKey(); peopleKey.setName( "张三" ); peopleKey.setIdcardno( "340123" ); People people = peopleRepository.findOne(peopleKey); return people; } } |
控制台上的输出结果:
1 | People [id=PeopleKey [name=张三, idcardno= 340123 ], age= 3 , address=分解分] |
三、EntityManager的验证,直接上代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | package com.my.model; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Embeddable; import javax.persistence.Entity; import javax.persistence.Id; //@Embeddable public class PeopleKey implements Serializable { // @Id // @Column(name = "name") private String name; // @Id // @Column(name = "idcardno") private String idcardno; public String getName() { return name; } public void setName(String name) { this .name = name; } public String getIdcardno() { return idcardno; } public void setIdcardno(String idcardno) { this .idcardno = idcardno; } @Override public String toString() { return "PeopleKey [name=" + name + ", idcardno=" + idcardno + "]" ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | package com.my.model; import java.io.Serializable; import javax.persistence.*; @Entity @Table (name = "people" ) @IdClass (PeopleKey. class ) public class People { // @EmbeddedId // private PeopleKey id; @Column (name = "age" ) private int age; @Column (name = "address" ) private String address; // public PeopleKey getId() { // return id; // } // // public void setId(PeopleKey id) { // this.id = id; // } // @Id @Column (name = "name" ) private String name; @Id @Column (name = "idcardno" ) private String idcardno; public String getName() { return name; } public void setName(String name) { this .name = name; } public String getIdcardno() { return idcardno; } public void setIdcardno(String idcardno) { this .idcardno = idcardno; } public int getAge() { return age; } public People() { super (); } public void setAge( int age) { this .age = age; } public String getAddress() { return address; } public void setAddress(String address) { this .address = address; } @Override public String toString() { return "People [age=" + age + ", address=" + address + ", name=" + name + ", idcardno=" + idcardno + "]" ; } }<br><br> |
测试:
1 2 3 4 5 6 7 8 9 | @RequestMapping (value = "/useEntityManager" ) public void findUseEntityManager() throws Exception { PeopleKey peopleKey = new PeopleKey(); peopleKey.setName( "张三" ); peopleKey.setIdcardno( "340123" ); People people = entityManager.find(People. class ,peopleKey); System.out.println(people.toString()); } |
结果:
1 | People [age= 3 , address=分解分, name=张三, idcardno= 340123 ] |
参考网址:
1、https://www.cnblogs.com/linjiqin/archive/2011/03/09/1978680.html
2、http://blog.youkuaiyun.com/qq_35056292/article/details/77892012
3. https://www.cnblogs.com/boywwj/p/8031106.html