【Java技术指南】「JPA编程专题」让你不再对JPA技术中的“持久化型注解”感到陌生了(二)

简介: 【Java技术指南】「JPA编程专题」让你不再对JPA技术中的“持久化型注解”感到陌生了

【Java技术指南】「JPA编程专题」让你不再对JPA技术中的“持久化型注解”感到陌生了(一)https://developer.aliyun.com/article/1471007


@Column

默认情况下,JPA 持续性提供程序假设每个实体的持久字段存储在其名称与持久字段的名称相匹配的数据库表列中。 使用 @Column 批注: 将持久字段与其他名称关联(如果默认列名难于处理、与事先存在的数据模型不兼容或作为数据库中的列名无效) 将持久字段与辅助表中的列关联(请参阅 @SecondaryTable ) 微调数据库中列的特征

@Column 属性


如何使用此批注使 JPA 将 empId 持久保存到辅助表 EMP_HR 中的列 EMP_NUM 。默认情况下,JPA 将 empName 持久保存到主表 Employee 中的列 empName 。

@Column

java

复制代码

@Entity
@SecondaryTable(name="EMP_HR")
public class Employee implements Serializable {  
  @Column(name="EMP_NUM", table="EMP_HR")
  private Long empId;
  private String empName;
}

@UniqueConstraint

默认情况下,JPA持久化提供程序假设所有列均可以包含重复值。

使用@UniqueConstraint注解指定将在为主表或辅助表生成的DDL中包含一个唯一约束,或者,您可以在列级别指定唯一约束。

属性状态

显示了如何使用此注解对主表 EMP 中的列 EMP_ID 和 EMP_NAME 指定一个唯一约束,使用唯一约束的 @Table。

java

复制代码

@Entity
@Table(
name="EMP",
uniqueConstraints={@UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"})}
)
public class Employee implements Serializable {
    ...
}

@Version

默认情况下,JPA持久化提供程序假设应用程序负责数据一致性。

使用@Version注解通过指定用作其乐观锁定值的实体类的版本字段或属性来启用 JPA 管理的乐观锁定(推荐做法)。

  • 选择版本字段或属性时,确保:
  • 每个实体只有一个版本字段或属性
  • 选择一个持久保存到主表的属性或字段(请参阅 @Table )
  • 您的应用程序不修改版本属性或字段

如何使用此注解将属性getVersionNum指定为乐观锁定值。在该示例中,该属性的列名设置为OPTLOCK(请参阅 @Column ),而非属性的默认列名。

@Version

java

复制代码

@Entity 
public class Employee implements Serializable {
    ...
  @Version
  @Column(name="OPTLOCK")
  protected int getVersionNum() {
    return versionNum;
  }
    ...
}

@Embeddable 和 @Embedded

  • 使用 @Embeddable 批注指定一个类,该类的实例存储为拥有实体的固有部分并共享该实体的身份。嵌入对象的每个持久属性或字段都将映射到实体的数据库表。
  • 类 EmploymentPeriod 在用作为 @Embedded 的持久字段的类型时可以嵌套到实体中.

java

复制代码

@Embeddable
public class EmploymentPeriod {
  java.util.Date startDate;
  java.util.Date endDate;
  ...
}

@Embedded

  • 使用 @Embedded 批注指定一个持久字段,该字段的 @Embeddable 类型可以存储为拥有实体的固有部分,并共享该实体的身份。
  • 嵌入对象的每个持久属性或字段均映射到拥有实体的数据库表。
  • 可以结合使用 @Embedded 和 @Embeddable 以建立严格所有权关系的模型,以便在删除了拥有对象的情况下还将删除被拥有的对象。嵌入的对象不应映射到多个表。
  • @Embeddable 类中指定的列定义适用于 @Embedded 类。
  • 如果要覆盖这些列定义,请使用 @AttributeOverride 。
  • @Embeddable 类 EmploymentPeriod可以使用指定的属性覆盖嵌入到实体类中。

java

复制代码

@Entity
public class Employee implements Serializable{...
@Embedded
@AttributeOverrides({
@AttributeOverride(name="startDate", column=@Column("EMP_START")),
@AttributeOverride(name="endDate", column=@Column("EMP_END"))
)
public EmploymentPeriod getEmploymentPeriod() {}}

@EmbeddedId

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

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

  • 它是一个普通的旧式 Java 对象 (POJO) 类。
  • 它必须为 public ,并且必须有一个 public 无参数构造函数。
  • 如果使用基于属性的访问,则主键类的属性必须为 public 或 protected 。
  • 它必须是可序列化的。
  • 它必须定义 equals 和 hashCode 方法。
  • 这些方法的值相等性的语义必须与键映射到的数据库类型的数据库相等性一致。

java

复制代码

@Embeddable
public class EmployeePK implements Serializable{
  private String name;
  private long id;
  public EmployeePK()  {    }
  //setter and getter
  public int hashCode() {
    return (int) name.hashCode() + id;
  }
  public boolean equals(Object obj) {
    if (obj == this) return true;
    if (!(obj instanceof EmployeePK)) return false;
    if (obj == null) return false;
    EmployeePK pk = (EmployeePK) obj;
    return pk.id == id && pk.name.equals(name);
    }
  }
@Entity
public class Employee implements Serializable{
  EmployeePK primaryKey;
  public Employee(){}
  @EmbeddedId
  public EmployeePK getPrimaryKey()  {
    return primaryKey;
  }
  public void setPrimaryKey(EmployeePK pk){
    primaryKey = pk;
  } 
  ...
}

@MappedSuperclass

  • 使用 @MappedSuperclass 批注指定一个实体类从中继承持久字段的超类。当多个实体类共享通用的持久字段或属性时,这将是一个方便的模式。
  • 您可以像对实体那样使用任何直接和关系映射批注(如 @Basic 和 @ManyToMany)对该超类的字段和属性进行批注,但由于没有针对该超类本身的表存在,因此这些映射只适用于它的子类。继承的持久字段或属性属于子类的表。
  • 可以在子类中使用 @AttributeOverride 或 @AssociationOverride 批注来覆盖超类的映射配置。

如何使用此批注将 Employee 指定为映射超类。如何扩展实体中的此超类,以及如何在实体类中使用 @AttributeOverride 以覆盖超类中设置的配置。

java

复制代码

@MappedSuperclass
public class Employee {
@Id
protected Integer empId;
 
@Version
protected Integer version;
 
@ManyToOne
@JoinColumn(name="ADDR")
protected Address address;
 
public Integer getEmpId() { 
        ...
    }
 
public void setEmpId(Integer id) { 
        ... 
    }
 
public Address getAddress() {
        ... 
    }
 
public void setAddress(Address addr) { 
        ... 
    }
}
@MappedSuperclass
@Entity
@AttributeOverride(name="address", column=@Column(name="ADDR_ID"))
public class PartTimeEmployee extends Employee {
@Column(name="WAGE")
protected Float hourlyWage;
public PartTimeEmployee() {
        ...
    }
public Float getHourlyWage() { 
        ... 
    }
public void setHourlyWage(Float wage) { 
        ... 
    }
}

@EntityListeners

@EntityListeners将一个或多个实体监听程序类与 @Entity 或 @MappedSuperclass 关联,条件是您需要在指定的生命周期事件发生时执行逻辑。

  • 不希望在实体 API 中公开生命周期监听程序方法。
  • 要在不同的实体类型之间共享生命周期监听程序逻辑。
  • 当实体或子类上发生生命周期事件时,JPA 持续性提供程序将按监听程序定义的顺序通知每个实体监听程序,并调用使用相应的生命周期事件类型进行批注的实体监听程序方法(如果有)。

实体监听程序类具有以下特征:

  • 它是一个普通的旧式 Java 对象 (POJO) 类
  • 它有一个或多个具有以下签名的回调方法:
  • public void (Object)
  • 可以指定参数类型 Object ,或实体监听程序将与其关联的实体类的类型。
  • 它用一个或多个生命周期事件批注对每个回调方法进行批注。
  • 一个生命周期事件只能与一个回调监听程序方法关联,但某个给定的回调监听程序方法可以与多个生命周期事件关联。
  • 如果使用实体监听程序,则可以管理哪些实体监听程序使用

@EntityListeners 属性

显示了您可以将多个生命周期事件与给定的实体监听程序类方法关联,但任何给定的生命周期事件只能在实体监听程序类中出现一次。

java

复制代码

@Entity
@EntityListeners(value={EmployeePersistListner.class, 
  EmployeeRemoveListener.class})
  public class Employee implements Serializable {
    ...
} 
  public class EmployeePersistListener {
  @PrePersist
  public void employee PrePersist(Object employee) {}};
public class EmployeeRemoveListener {
  @PreRemove
  @PostRemove
  public void employeePreRemove(Object employee) { } ...}

@ExcludeDefaultListeners

如果默认监听程序行为不适用,请使用 @ExcludeDefaultListeners 批注覆盖(并阻止)针对给定 @Entity 或 @MappedSuperclass 执行的默认监听程序。

java

复制代码

@Entity
  @ExcludeDefaultListeners
  public class Employee implements Serializable {
    ...
}


相关文章
|
4天前
|
存储 监控 安全
单位网络监控软件:Java 技术驱动的高效网络监管体系构建
在数字化办公时代,构建基于Java技术的单位网络监控软件至关重要。该软件能精准监管单位网络活动,保障信息安全,提升工作效率。通过网络流量监测、访问控制及连接状态监控等模块,实现高效网络监管,确保网络稳定、安全、高效运行。
31 11
|
14天前
|
XML Java 编译器
Java注解的底层源码剖析与技术认识
Java注解(Annotation)是Java 5引入的一种新特性,它提供了一种在代码中添加元数据(Metadata)的方式。注解本身并不是代码的一部分,它们不会直接影响代码的执行,但可以在编译、类加载和运行时被读取和处理。注解为开发者提供了一种以非侵入性的方式为代码提供额外信息的手段,这些信息可以用于生成文档、编译时检查、运行时处理等。
50 7
|
17天前
|
Java 程序员
Java编程中的异常处理:从基础到高级
在Java的世界中,异常处理是代码健壮性的守护神。本文将带你从异常的基本概念出发,逐步深入到高级用法,探索如何优雅地处理程序中的错误和异常情况。通过实际案例,我们将一起学习如何编写更可靠、更易于维护的Java代码。准备好了吗?让我们一起踏上这段旅程,解锁Java异常处理的秘密!
|
1天前
|
算法 Java 调度
java并发编程中Monitor里的waitSet和EntryList都是做什么的
在Java并发编程中,Monitor内部包含两个重要队列:等待集(Wait Set)和入口列表(Entry List)。Wait Set用于线程的条件等待和协作,线程调用`wait()`后进入此集合,通过`notify()`或`notifyAll()`唤醒。Entry List则管理锁的竞争,未能获取锁的线程在此排队,等待锁释放后重新竞争。理解两者区别有助于设计高效的多线程程序。 - **Wait Set**:线程调用`wait()`后进入,等待条件满足被唤醒,需重新竞争锁。 - **Entry List**:多个线程竞争锁时,未获锁的线程在此排队,等待锁释放后获取锁继续执行。
24 12
|
14天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
14天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
38 3
|
14天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
19天前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
55 5
|
19天前
|
开发框架 安全 Java
Java 反射机制:动态编程的强大利器
Java反射机制允许程序在运行时检查类、接口、字段和方法的信息,并能操作对象。它提供了一种动态编程的方式,使得代码更加灵活,能够适应未知的或变化的需求,是开发框架和库的重要工具。
35 2
|
1月前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin