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

一、Spring Data Jpa 复合主键
1.1、编写一个复合主键类:PeopleKey
@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无参数的构造方法(在我这个实例中,我没有添加有参构造方法,所以采用默认的构造方法)
如果你在实体类里有有参构造方法,那么一定要有一个无参构造方法,否则运行的时候会报错
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
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 测试:
@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;
}
}
控制台上的输出结果:
People [id=PeopleKey [name=张三, idcardno=340123], age=3, address=分解分]
二、采用@IdClass来注解复合主键
过程和@Embeddable差不多,这里直接贴例子。
@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;
}
public class PeopleKey implements Serializable {
// @Id
// @Column(name = "name")
private String name;
// @Id
// @Column(name = "idcardno")
private String idcardno;
}
采用这个方法的我参考博客里有一篇,写的比较详细,但是感觉这个方法不好,本身就已经在PeopleKey中把主键给封装了,但是在实体类People中还要把复合主键给加入进去,不够简介,采用第一种方法,就很简单,而且也体现了Java类封装的思想。
三、EntityManager的验证,直接上代码
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 + "]";
}
}
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 + "]";
}
}
测试:
@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());
}
结果:
People [age=3, address=分解分, name=张三, idcardno=340123]
参考博客:
1、https://www.cnblogs.com/linjiqin/archive/2011/03/09/1978680.html