组合主键
主键最常见的是单字段主键,组合主键使用两个及以上的字段作为主键,常用于多个字段能唯一标示一条记录的表。比如,股票数据表,股票代码、日期和收盘价作为主键。每支股票,在一个特定日期,只能有一个收盘价。
数据库管理系统使用MySQL,创建一个具有组合主键的表Person。
CREATE TABLE PERSON (
name VARCHAR(255) NOT NULL,
age BIGINT UNSIGNED NOT NULL,
adress VARCHAR(255) ,
PRIMARY KEY (name, age)
) ENGINE = InnoDB;
JPA映射之@IdClass
定义工具类
package com.gxz.entities;
import java.io.Serializable;
public class PersonCompositeId implements Serializable {
private String name;
private long age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getAge() {
return age;
}
public void setAge(long age) {
this.age = age;
}
}
该工具类的属性必须和实体类的@Id属性完全匹配。包括数量、名字,不能有额外的属性。定义实体类
package com.gxz.entities;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;
@Entity
@Table
@IdClass(PersonCompositeId.class)
public class Person {
private String name;
private long age;
private String adress;
@Id
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Id
public long getAge() {
return age;
}
public void setAge(long age) {
this.age = age;
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
}
该实体类有两个属性标示为@Id,表示主键为组合主键,主键属性为name、age。相应地,工具类PersonCompositeId必须有两个属性,分别为name、age。注意,此处指的是工具类必须有getName、setName、getAge、setAge,而不是指必须有字段name、age,注意区分属性和字段的区别。@IdClass(PersonCompositeId.class):表示使用工具类PersonCompositeId定义组合主键。另外,工具类PersonCompositeId必须实现序列化Serializable,否则,报出如下异常。[PersistenceUnit: EntityMappings] Unable to build Hibernate SessionFactory
Composite-id class must implement Serializable: com.gxz.entities.PersonCompositeId
Composite-id class must implement Serializable: com.gxz.entities.PersonCompositeId
持久化
Person person = new Person();
person.setName("李四");
person.setAge(40);
person.setAdress("广州市");
manager.persist(person);
根据id查找实体
PersonCompositeId personCompositeId = new PersonCompositeId();
personCompositeId.setName("张三");
personCompositeId.setAge(50);
Person person = manager.find(Person.class, personCompositeId);
if (person != null) {
System.out.println("name:" + person.getName() + " age:" + person.getAge());
}
JPA映射之@EmbeddedId
定义工具类
package com.gxz.entities;
import java.io.Serializable;
import javax.persistence.Embeddable;
@Embeddable
public class PersonCompositeId implements Serializable {
private String name;
private long age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getAge() {
return age;
}
public void setAge(long age) {
this.age = age;
}
}
@Embeddable:表示该工具类用于组合主键,属性就是组合主键的属性。
定义实体类
package com.gxz.entities;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table
public class Person {
private PersonCompositeId personCompositeId;
@EmbeddedId
public PersonCompositeId getPersonCompositeId() {
return personCompositeId;
}
public void setPersonCompositeId(PersonCompositeId personCompositeId) {
this.personCompositeId = personCompositeId;
}
private String adress;
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
}
@EmbeddedId:表示该属性是组合主键,类型是组合主键工具类。持久化
PersonCompositeId personCompositeId = new PersonCompositeId();
personCompositeId.setName("搜噶");
personCompositeId.setAge(100);
person.setPersonCompositeId(personCompositeId);
person.setAdress("广州市");
manager.persist(person);
transaction.commit();
两种映射方式的比较
第一种方式,工具类和实体类有一模一样的属性,属于冗余,第二种方式则没有没有冗余,显得更加科学。因此,实际工作中,第二种方式更加常用。