上一篇博客简单介绍了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) 重写equalshashCode方法。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

2、http://blog.csdn.net/qq_35056292/article/details/77892012 

SpringData JPA复合主键的更多相关文章

  1. springboot jpa 复合主键

    https://blog.csdn.net/wyc_cs/article/details/9031991 创建一个复合主键类 public class LevelPostMultiKeysClass ...

  2. 【hibernate/JPA】注解方式实现 复合主键【spring boot】

    1>hibernate/JPA实现复合主键的思路:是将所有的主键属性封装在一个主键类中,提供给需要复合主键的实体类使用. 2>主键类的几点要求: . 使用复合主键的实体类必须实现Seria ...

  3. 【hibernate/JPA】对实体类的的多个字段建立唯一索引,达到复合主键的效果【spring boot】注解创建唯一索引和普通索引

    对实体类的的多个字段建立唯一索引,达到复合主键的效果 package com.sxd.swapping.domain; import lombok.Getter; import lombok.Sett ...

  4. JPA联合主键

    联合主键也就是说需要多个字段才能确定数据库记录中的唯一一行.这样就需要多个字段一起,组成主键,也叫联合主键.例如飞机航线,我们需要知道飞机起飞的地点以及飞机降落的地点.所以需要飞机起飞的地点和降落的地 ...

  5. Hibernate 表映射 主键生成策略与复合主键

    主要分析三点: 一.数据表和Java类的映射 : 二.单一主键映射和主键的生成策略 : 三.复合主键的表映射 : 一.数据表和Java类的映射  Hibernate封装了数据库DDL语句,只需要将数据 ...

  6. hibernate复合主键

    需要用到实体类Role的主键和Menu的主键结合起来作为实体类RoleMenu的主键,那么通过Hibernate具体实现如下: RoleMenu实体类:(注意该实体类需要实现Serializable接 ...

  7. 复合主键@IdClass

    有时一个实体的主键可能同时为多个,例如同样是之前使用的“CustomerEO”实体,需要通过name和email来查找指定实体,当且仅当name和email的值完全相同时,才认为是相同的实体对象.要配 ...

  8. Hibernate征途(七)之复合主键映射和集合映射

    把这两种映射放到一起说,是因为这两种映射不像前面的复用型映射.数量和方向型映射那么分类鲜明,所以放到了这个“其他”里面. 复合主键映射 在关系模型中,复合主键和其他的主键方式没有很大区别,但是反映到对 ...

  9. Hibernate复合主键映射

    目录: 1. 实现方式一:将复合主键对应的属性与实体其他普通属性放在一起 2. 实现方式二:将主键属性提取到一个主键类中,实体类只需包含主键类的一个引用 在日常开发中会遇到这样一种情况,数据库中的某张 ...

随机推荐

  1. Gtk-WARNING **: cannot open display: :0.0之解决

    当使用su 到另外一个用户运行某个程序,而这个程序又要有图形显示的时候,就有可能有下面提示: root@dt:~# sudo -i -u keji google-chrome No protocol ...

  2. [Jenkins]怎样自定义发出邮件的 From Email Address 和 From Name

    在Jenkins上建了一个执行SoapUI的task,想要自定义发送邮件的地址和姓名,怎么办呢? 在Editable Email Notification里面添加Pre-send Script 脚本如 ...

  3. MongoDB管理与开发实战详解文摘

    第1篇 基础篇 第1章 MongoDB简介 关系型数据库面临的问题:数据库并发负载高,海量数据存储与访问,数据库数据越来越大,事务管理的负担,关系型数据库读.写实时性的忽略,多表关联查询被弱化 第2章 ...

  4. HTTP 499 状态码 nginx下 499错误

    日志记录中HTTP状态码出现499错误有多种情况,我遇到的一种情况是nginx反代到一个永远打不开的后端,就这样了,日志状态记录是499.发送字节数是0. 老是有用户反映网站系统时好时坏,因为线上的产 ...

  5. Android-系统绘图真相

    系统绘图真相:这篇博客是专门讲解,系统内部是如何控制图片的变化,例如:图片缩放/图片旋转/图片平移/等等 注意:⚠️在真实开发过程中:关于图片的 图片缩放/图片旋转/图片平移/等等 操作 是使用动画A ...

  6. Docker在github上的站点

    https://github.com/docker (docker在github上的官方地址) https://github.com/dockerfile (docker官方镜像的Dockerfile ...

  7. js判断是移动端还是PC端访问网站

    window.location.href = /Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent) ? "htt ...

  8. JAVA—Filter

    过滤器 Filter 1. Filter简介. filter 是对客户端访问资源的过滤,符合条件放行,不符合条件不放行, 并且可以对目标资源访问前后进行逻辑处理. 2. Filter 的API 详解. ...

  9. ES6——Class的继承

    class 的继承和使用. 子类继承父类,使用extends关键字. 为父类知道那个静态方法,使用 static方法名字super: 在构造函数中,可以当一个函数来使用,相当于调用父类的构造函数. 在 ...

  10. 创建可复用的自定义 ASP.NET MVC Helpers

    通常,在ASP.NET MVC项目中App_Code目录下新建.cshtml编写类似下方的代码就能创建自定义的MVC Helper了, 假设文件名为StrHelper.cshtml,那么在别的视图中的 ...