使用JPA主键@Id,@IdClass,@Embeddable,@EmbeddedId问题

目录
  • JPA主键@Id,@IdClass,@Embeddable,@EmbeddedId
    • 1、自动主键
    • 2、应用设置主键
    • 3、复合主键
    • 4、嵌入式主键
  • @EmbeddedId和@IdClass的区别
    • @idClass
    • @EmbeddedId

JPA主键@Id,@IdClass,@Embeddable,@EmbeddedId

1、自动主键

默认情况下,主键是一个连续的64位数字(long),它由ObjectDB自动为存储在数据库中的每个新实体对象自动设置。

数据库中的第一个实体对象的主键是1,第二个实体对象的主键是2等等。

当从数据库中删除实体对象时,主键值不会被回收。

一个实体的主键值可以通过声明一个主键字段来访问:

@Entity
public class Project {
    @Id @GeneratedValue long id; // still set automatically
}
  • @id标注将字段标记为一个主键字段。当定义主键字段时,主键值将被ObjectDB自动注入到该字段中。
  • @generatedvalue注释指定主键是由ObjectDB自动分配的

2、应用设置主键

如果一个实体有一个没有@generatedvalue标记的主键字段,则不会生成自动主键值,并且应用程序负责通过初始化主键字段来设置主键。这必须在持久化实体对象的任何尝试之前完成。

@Entity
public class Project {
    @Id long id; // must be initialized by the application
}

应用程序设置的主键字段可以有以下类型:

● 原始类型: boolean, byte, short, char, int, long, float, double.

● java.lang包中的包装类型:Byte, Short, Character, Integer, Long, Float, Double.

● java.math.BigInteger, java.math.BigDecimal.

● java.lang.String.

● java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp.

● 枚举类型

● 引用一个实体对象

3、复合主键

复合主键由多个主键字段组成。每个主键字段必须是上面列出的支持类型之一。

例如,以下项目实体类的主键由两个字段组成:

@Entity @IdClass(ProjectId.class)
public class Project {
    @Id int departmentId;
    @Id long projectId;
}

当一个实体有多个主键字段时,JPA需要定义一个特殊的ID类,该类是使用@idclass注释附加到实体类的。ID类反映了主键字段,它的对象可以表示主键值:

Class ProjectId {
    int departmentId;
    long projectId;
}

ObjectDB不强制定义ID类。但是,如果实体对象必须按照检索实体部分中所示的主键来检索实体对象,那么就需要ID类。

4、嵌入式主键

表示复合主键的另一种方法是使用可嵌入的类:

@Entity
public class Project {
    @EmbeddedId ProjectId id;
}
@Embeddable
Class ProjectId {
    int departmentId;
    long projectId;
}

主键字段是在可嵌入类中定义的。

该实体包含一个单独的主键字段,该字段用@EmbeddedId 注释,并包含一个可嵌入类的实例。

当使用这个表单时,没有定义一个单独的ID类,因为可嵌入的类本身可以表示完整的主键值。

@EmbeddedId和@IdClass的区别

@idClass

使复合主键类成为非嵌入类,使用 @IdClass 批注为实体指定一个复合主键类(通常由两个或更多基元类型或 JDK 对象类型组成)。从原有数据库映射时(此时数据库键由多列组成),通常将出现复合主键。

复合主键类具有下列特征:

  • 它是一个普通的旧式 Java 对象 (POJO) 类。
  • 它必须为 public,并且必须有一个 public 无参数构造函数。
  • 如果使用基于属性的访问,则主键类的属性必须为 public 或 protected。
  • 它必须是可序列化的。
  • 它必须定义 equals 和 hashCode 方法。
  • 这些方法的值相等性的语义必须与键映射到的数据库类型的数据库相等性一致。
  • 它的字段或属性的类型和名称必须与使用 @Id 进行批注的实体主键字段或属性的类型和名称相对应。
package com.model;
import java.io.Serializable;
public class SysUserRoleId implements Serializable{ 
    /**
     *
     */
    private static final long serialVersionUID = 2606793267849167078L;
    private Long userId;
    private Long roleId;
     
    @Override
    public int hashCode(){
        int result = 1;
        result = userId.hashCode()+roleId.hashCode();
        return result;
    }
     
    @Override
    public boolean equals(Object obj){
    
        if(obj == null){
            return false;
        }
         
        if(this == obj){
            return true;
        }
         
        if(getClass() != obj.getClass()){
            return false;
        }
         
        final SysUserRoleId other = (SysUserRoleId) obj;
        if(other.getUserId().equals(this.userId) && other.getRoleId().equals(this.roleId)){
            return true;
        }
         
        return false;
    }
     
    public Long getUserId() {
        return userId;
    }
    public void setUserId(Long userId) {
        this.userId = userId;
    }
    public Long getRoleId() {
        return roleId;
    }
    public void setRoleId(Long roleId) {
        this.roleId = roleId;
    }  
}
package com.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;
  
@Entity
@Table(name="SYS_USER_ROLE")
@IdClass(SysUserRoleId.class)
public class SysUserRole {
    private Long userId;
    private Long roleId;
    public SysUserRole(){ 
    }
     
    public SysUserRole(Long userId,Long roleId){
        this.userId = userId;
        this.roleId = roleId;
    }
     
    @Id
    @Column(name="user_id")
    public Long getUserId() {
        return userId;
    }
    public void setUserId(Long userId) {
        this.userId = userId;
    }
     
    @Id
    @Column(name="role_id")
    public Long getRoleId() {
        return roleId;
    }
    public void setRoleId(Long roleId) {
        this.roleId = roleId;
    }    
}

@EmbeddedId

使复合主键类成为由实体拥有的嵌入类

使用 @EmbeddedId 批注指定一个由实体拥有的可嵌入复合主键类(通常由两个或更多基元类型或 JDK 对象类型组成)。从原有数据库映射时(此时数据库键由多列组成),通常将出现复合主键。

复合主键类具有下列特征:

  • 它是一个普通的旧式 Java 对象 (POJO) 类。
  • 它必须为 public,并且必须有一个 public 无参数构造函数。
  • 如果使用基于属性的访问,则主键类的属性必须为 public 或 protected。
  • 它必须是可序列化的。
  • 它必须定义 equals 和 hashCode 方法。
  • 这些方法的值相等性的语义必须与键映射到的数据库类型的数据库相等性一致。
package com.model;
import java.io.Serializable;
import javax.persistence.Column;
@SuppressWarnings("serial")
public class SysOrganizationRolePKId implements Serializable{
    private Long organizationId;
    private Long roleId;
     
    @Column(name="organization_id")
    public Long getOrganizationId() {
        return organizationId;
    }
    public void setOrganizationId(Long organizationId) {
        this.organizationId = organizationId;
    }
     
    @Column(name="role_id")
    public Long getRoleId() {
        return roleId;
    }
    public void setRoleId(Long roleId) {
        this.roleId = roleId;
    }     
}
package com.model;
import java.io.Serializable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
 
@Entity
@SuppressWarnings("serial")
@Table(name="SYS_ORGANIZATION_ROLE")
public class SysOrganizationRole implements Serializable{
    private SysOrganizationRolePKId sysOrganizationRolePKId;
 
    @EmbeddedId
    public SysOrganizationRolePKId getSysOrganizationRolePKId() {
        return sysOrganizationRolePKId;
    }
 
    public void setSysOrganizationRolePKId(
            SysOrganizationRolePKId sysOrganizationRolePKId) {
        this.sysOrganizationRolePKId = sysOrganizationRolePKId;
    }   
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Spring Data JPA 实体类中常用注解说明

    目录 javax.persistence 介绍 基本注解 关联关系注解 关于关系查询的一些注意事项 javax.persistence 介绍 Spring Data JPA 采用约定大于配置的思想,默认了很多东西 JPA是存储业务实体关联的实体来源,它显示定义了如何定义一个面向普通Java对象(POJO)作为实体,以及如何与管理关系实体提供一套标准 javax.persistence位于hibernate-jpa-**.jar 包里面 jpa类层次结构: JPA类层次结构的显示单元: 单元 描述

  • Spring Data JPA 建立表的联合主键

    最近遇到了一个小的问题,就是怎么使用 Spring Data JPA 建立表的联合主键?然后探索出了下面的两种方式. 第一种方式: 第一种方式是直接在类属性上面的两个字段都加上 @Id 注解,就像下面这样,给 stuNo 和 stuName 这两个字段加上联合主键: @Entity @Table(name = "student") public class Student { @Id @Column(name = "stu_no", nullable = false

  • Spring Data Jpa 复合主键的实现

    前言 这次大创有个需求,在数据库建表时发现,user表与project表的关系表 user_project的主键为复合主键: CREATE TABLE user_project( user_id INT(20), project_id INT(20), timestamp VARCHAR (50), donate_money DOUBLE(10,2), PRIMARY KEY (user_id,project_id) ); 在网上看了几篇博客,以及在spring boot干货群咨询(感谢夜升额耐

  • 使用JPA主键@Id,@IdClass,@Embeddable,@EmbeddedId问题

    目录 JPA主键@Id,@IdClass,@Embeddable,@EmbeddedId 1.自动主键 2.应用设置主键 3.复合主键 4.嵌入式主键 @EmbeddedId和@IdClass的区别 @idClass @EmbeddedId JPA主键@Id,@IdClass,@Embeddable,@EmbeddedId 1.自动主键 默认情况下,主键是一个连续的64位数字(long),它由ObjectDB自动为存储在数据库中的每个新实体对象自动设置. 数据库中的第一个实体对象的主键是1,第二

  • MyBatis获取数据库自生成的主键Id详解及实例代码

    MyBatis获取数据库自生成的主键Id详解及实例代码 在使用MySQL数据库时我们一般使用数据库的自增主键自动产生主键.如果在插入主表时,我们需要同时插入从表的数据,这时我们通常需要知道主表插入时自动产生的主键Id值. 下面介绍使用MyBatis进行插入时,如何同时获取数据库自生成的主键: 1.XML配置文件 <insert id="insert" parameterType="Person" useGeneratedKeys="true"

  • MyBatis在insert插入操作时返回主键ID的配置(推荐)

    很多时候,在向数据库插入数据时,需要保留插入数据的id,以便进行后续的update操作或者将id存入其他表作为外键. 但是,在默认情况下,insert操作返回的是一个int值,并且不是表示主键id,而是表示当前SQL语句影响的行数... 接下来,我们看看MyBatis如何在使用MySQL和Oracle做insert插入操作时将返回的id绑定到对象中. MySQL用法: <insert id="insert" parameterType="com.test.User&qu

  • THINKPHP在添加数据的时候获取主键id的值方法

    在使用ThinkPHP新增数据后可以很方便的获取自动增长型的主键值. $Model = D('Blog'); $data['name'] = 'test'; $data['title'] = '测试标题'; $data['content'] = '测试内容'; $result = $Model->add($data); if ($result){ $id = $result; // 获取数据库写入数据的主键 }else{ exit($Model->getError()); } 如果你的数据表主

  • MySQL生产库Insert了2次同样的记录但是主键ID是不一样的问题的分析过程

    Email里面收到朋友laopan的求助 laopan:insert into HudsonResult(JobID,EnvironmentID,FirstSessionID,RerunSessionID,State,Desp,OtherInfo) values ((select ID from Hudson where Stream='A7510_R52_Integration' and State='N' and pakName='needCompile' and User='jinhaiz

  • Python3 操作 MySQL 插入一条数据并返回主键 id的实例

    Python 中貌似并没有直接返回插入数据 id 的操作(反正我是没找到),但是我们可以变通一下,找到最新插入的数据 #!/usr/bin/env python3 # -*- coding: UTF-8 -*- import pymysql db = pymysql.connect(**db_conf) cursor = db.cursor() cursor.execute(sql) # 最后插入行的主键id print(cursor.lastrowid) # 最新插入行的主键id print(

  • mybatis-plus的selectById(或者selectOne)在根据主键ID查询实体对象的时候偶尔会出现null的问题记录

    mybatis-plus的selectById/selectOne查询结果偶尔出错(为null)的问题记录 错误截图: 亲测重复执行此段代码10次中大概会有连续的2次出现结果为null的情况. 由于后续还需引用到这个查询结果的某些字段信息,会导致程序出现空指针异常,故投机取巧做了如下处理(加了一个while循环让其一直执行selectById(或者selectOne)直到查询结果不为空): 但这终归不是从根本上解决了问题.我也不清白他出现这个问题的根本原因是什么. 到此这篇关于mybatis-p

  • mybatis-plus主键id生成、字段自动填充的实现代码

    一.主键id的生成 数据库表里通常都会有一个主键id,来作为这条数据的唯一标识. 常见的方式 1.数据库自动增长 这种很常见了,可以做到全库唯一.因为id是天然排序的,对于涉及到排序的操作会很方便. 2.UUID 上面的自动增长,虽然简单,但是对于分表这样的操作来说就比较麻烦.因为你在第二张插入数据的时候,需要拿到上一张表最后一个数据的id. UUID则不同,每次都一个随机唯一的值,不过因为是随机,所以也就没有排序了. 3.redis redis也可以用来生成id,利用redis的原子操作.好处

  • mybatis中insert主键ID获取和多参数传递的示例代码

    一.插入数据主键ID获取 一般我们在做业务开发时,经常会遇到插入一条数据并使用到插入数据的ID情况.如果先插入在查询的话需要多一次sql查询,未免效率太低.因此mybatis也有提供插入数据并返回主键ID的方式.如下 1.Insert/update 1.1.属性解释 keyProperty selectKey 语句结果应该被设置的目标属性.如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表. resultType 结果的类型.MyBatis 通常可以推算出来,但是为了更加确定写上也不会有什

  • Mybatis批量插入返回插入成功后的主键id操作

    我们都知道Mybatis在插入单条数据的时候有两种方式返回自增主键: 1.对于支持生成自增主键的数据库:增加 useGenerateKeys和keyProperty ,<insert>标签属性. 2.不支持生成自增主键的数据库:使用<selectKey>. 但是怎么对批量插入数据返回自增主键的解决方式网上看到的还是比较少,至少百度的结果比较少. Mybatis官网资料提供如下: First, if your database supports auto-generated key

随机推荐