首页 > 代码库 > 组合主键及JPA映射

组合主键及JPA映射

组合主键

主键最常见的是单字段主键,组合主键使用两个及以上的字段作为主键,常用于多个字段能唯一标示一条记录的表。比如,股票数据表,股票代码、日期和收盘价作为主键。每支股票,在一个特定日期,只能有一个收盘价。
数据库管理系统使用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();

两种映射方式的比较

第一种方式,工具类和实体类有一模一样的属性,属于冗余,第二种方式则没有没有冗余,显得更加科学。因此,实际工作中,第二种方式更加常用。


组合主键及JPA映射