Hibernate中的标识符为实体的主键属性建模。 它有助于我们唯一地标识JPA实体。 每个实体都必须定义一个标识符。 同样,它可以是简单的也可以是复合的。
我们可以通过几种方式定义一个Hibernate标识符。 在本教程中,我们将学习如何做。
简单(单值)标识符:
如果我们有一个可以唯一标识我们实体的属性,则可以使用@Id注释对该属性进行简单注释:
Java
@Entity
public class Employee {@Idprivate Integer empId;...
}
请记住,用@Id注释的属性应为以下类型之一:
- 任何Java基本类型或任何原始包装器类型
- 串
- 任何Java 日期类型,或者
- BigDecimal或BigInteger
简单生成的标识符:
如果我们希望自动生成id值怎么办? 为此,我们可以更进一步,在标识符字段上使用@GeneratedValue批注:
Java
@Entity
public class Employee {@Id@GeneratedValuepublic Integer empId;...
}
当使用@GeneratedValue时 ,Hibernate在保留实体的同时会为我们的id列生成值。 对我们而言,重要的是要记住, 我们只能自动生成整数类型( int,short或long )或UUID 。
另外,我们有四种不同的密钥生成策略可用于自动生成标识符的值:
Hibernate使用AUTO密钥生成策略作为默认策略。 从一个JPA持久性提供者到另一个JPA持久性提供者, AUTO策略的行为略有不同。 对于 Hibernate,如果 identifier属性的类型为UUID,则它使用UUIDGenerator ,否则默认为序列生成策略。
UUID生成仅在Hibernate 5和更高版本中受支持,并且长度为36个字符:
Java
@Entity
public class Employee {@Id@GeneratedValueprivate UUID empId;...
}
生成的UUID的格式为“ 4ee5a777-7981-4e01-06ab-19aabb2eaa122”。
对于IDENTITY生成策略,Hibernate使用IdentityGenerator生成标识符值。 这些值是由数据库的标识列生成的,并且会自动递增:
Java
@Entity
public class Employee {@Id@GeneratedValue (strategy = GenerationType.IDENTITY)private Integer empId;...
}
使用此策略的主要缺点是它不支持批处理JDBC插入。
在这里,顾名思义,数据库序列用于生成我们的标识符的值。 Hibernate在内部使用SequenceStyleGenerator类来实现它。 如果我们的数据库不支持序列,它将自动切换到TABLE密钥生成策略。
SEQUENCE生成器为每个序列生成唯一的值。 我们可以指定我们希望使用的数据库顺序:
Java
@Entity
public class Employee {@Id@GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "emp_generator")@SequenceGenerator(name = "emp_generator",sequenceName = "emp_seq", allocationSize = 100)public Integer empId;...
}
否则,Hibernate将使用隐式命名的序列hibernate_sequence :
Java
@Entity
public class Employee {@Id@GeneratedValue(strategy = GenerationType.SEQUENCE)public Integer empId;...
}
为我们的标识符字段生成值。
Hibernate TableGenerator使用一个表,该表能够保存标识符生成值的多个段。 除非指定,否则Hibernate默认使用hibernate_sequences表:
Java
@Entity
public class Employee {@Id@GeneratedValue(strategy = GenerationType.TABLE)public Integer empId;...
}
我们可以使用@TableGenerator来指定用于生成值的数据库表:
Java
@Entitypublic class Employee {@Id@GeneratedValue(strategy = GenerationType.TABLE, generator = "emp_generator") @TableGenerator(name = "emp_generator",table = "emp_generator_tbl",schema = "employees")public Integer empId;...}
TABLE策略的伸缩性不是很好,并且性能很差,因此在实际的实现中很少使用。 对于所有支持序列的数据库,我们总是应该优先使用SEQUENCE生成策略,而大多数现代数据库通常都会这样做。
复合标识符:
Hibernate还允许我们定义一个复合标识符。 要定义组合标识符,我们创建一个主键类,其中包含构成组合键的持久属性。 根据JPA规范, 我们的主键类必须为:
- 用@EmbeddedId或@IdClass注释进行注释
- 公开并有一个公开的无参数构造函数
- 可序列化
- 实现equals()和hashCode()方法
组成合成的属性可以是basic,composite或ManyToOne。 但是,集合和OneToOne属性被认为不合适。
1.使用
定义和使用复合键的一种方法是使用@EmbeddedId批注。
因此,让我们开始定义主键类并使用@Embeddable对其进行注释 :
Java
@Embeddable
public class EmployeePurchasesPK implements Serializable {private long empId;private long productId;//equals() and hashCode() methods...
}
现在,我们可以使用@EmbeddedId批注轻松地从我们的实体中引用此类:
Java
@Entity
public class EmployeePurchases {@EmbeddedIdprivate EmployeePurchasesPK primaryAttributes;...
}
要使用我们的实体类设置或检索主键属性,我们将具有以下内容:
Java
EmployeePurchasesPK primaryAttributes = new EmployeePurchasesPK();
primaryAttributes.setEmpId(1001);
primaryAttributes.setProductId(7822);EmployeePurchases empPurchases = new EmployeePurchases();
empPurchases.setPrimaryAttributes(primaryAttributes);
...
显然,我们的EmployeePurchases实体具有一个由empId和productId组成的复合键。
2.使用
使用@IdClass创建复合键时,我们可以使用@Id批注在主类中定义所有合成属性。 我们的主键类中的代码保持原样,但仅充当“影子” :
Java
@Entity
@IdClass(EmployeePurchasesPK.class)
public class EmployeePurchases {@Idprivate long empId;@Idprivate long productId;...}
通过这种方法,我们可以使用主要实体类的getter / setter方法直接设置键值:
Java
EmployeePurchases empPurchases = new EmployeePurchases();
empPurchases.setEmpId(1011);
empPurchases.setProductId(9331);
...
但是,此方法无法为我们提供标识符和实体对象之间的清晰区分。
派生标识符:
在Hibernate中,我们可以选择使用@MapsId注释从其关联之一复制实体的标识符值 :
Java
public class EmployeeHistory {@Idprivate long id;@OneToOne@MapsIdprivate Employee employee;...}
在这里,我们的EmployeeHistory实例将具有与相应Employee实例完全相同的ID 。
结论:
在本教程中,我们研究了在Hibernate中定义标识符的多种方法。 我们还介绍了不同的关键自动生成策略。
成为第一个发表评论的人。
翻译自: https://www.javacodegeeks.com/2019/04/identifiers-hibernate.html