两种方式:
1,建表时创建
2,建表后再添加主键
CREATE TABLE 表名 (
列名1 数据类型,
列名2 数据类型,
...
PRIMARY KEY (列名1, 列名2)
);
如果想给主键起个名字,可以这么写:
CREATE TABLE 表名 (
列名1 数据类型,
列名2 数据类型,
...
CONSTRAINT 联合主键名称 PRIMARY KEY (列名1, 列名2)
);
ALTER TABLE 表名
ADD CONSTRAINT 联合主键名称 PRIMARY KEY (列名1, 列名2);
如果创建的时候报错multiple primary keys for table “student_info” are not allowed,
那就要先删除原来的表中的主键
ALTER TABLE 表名 DROP CONSTRAINT 联合主键名称;
常见的有三种方式:这里使用其中一种:
定义一个主键类,用@IdClass注解结合@id注解定义联合主键
现举例说明:
给学生成绩表Strudent_score定义联合主键,用@IdClass,结合@Id注解来定义表中的三个字段为联合主键
这个类应该是一个普通的Java类,它包含联合主键的所有字段,以及这些字段对应的getter和setter方法。并且重写equals和HashCode方法
public class StudentScorePK implements java.io.Serializable {
private int studentId;
private int subjectId;
private int score;
// getter和setter方法...
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final StudentScorePK other = (StudentScorePK) obj;
if (this.studentId != other.studentId || this.subjectId != other.subjectId || this.score != other.score) {
return false;
}
return true;
}
public int hashCode() {
int hash = 7;
hash = 31 * hash + this.studentId;
hash = 31 * hash + this.subjectId;
hash = 31 * hash + this.score;
return hash;
}
}
将使用@IdClass注解来指定使用联合主键StudentScorePK 的类——Student_score,然后使用@Id注解来标记联合主键的字段。
import org.hibernate.annotations.IdClass;
import org.hibernate.annotations.Id;
@IdClass(StudentScorePK.class)
public class StudentScore {
@Id
private int studentId;
@Id
private int subjectId;
@Id
private int score;
// 其他字段和方法...
}
有人可能问,为什么要重写equals和HashCode方法,
定义联合主键时需要重写equals()
和hashCode()
方法,这是因为这些方法在处理对象相等性比较以及哈希表操作(如Java的HashMap或HashSet)中起着核心作用。在没有自定义这些方法的情况下,它们默认实现是基于对象的内存地址进行比较的,这通常不符合业务逻辑中的实体相等性判断。
考虑以下几点原因:
相等性判断:
equals()
方法,那么即使两个实体的主键值相同,只要它们位于不同的内存位置,就会被当作不同的实体对待。哈希表操作:
hashCode()
和equals()
方法来正确地存储和查找元素。hashCode()
返回一个整数,用于快速定位到哈希表中的桶(bucket),而equals()
用于检查该桶中的元素是否是我们正在寻找的对象。Hibernate和其他ORM框架:
equals()
和hashCode()
方法来管理缓存并确保数据的一致性。因此,当定义联合主键时,我们需要为相应的实体类重写equals()
和hashCode()
方法,以便按照业务需求来正确地比较和操作这些实体。