Hibernate中的自然标识符是什么?
在阅读Hibernate文档时,我不断看到对自然标识符概念的引用。
这是否仅仅意味着实体所具有的id由于它所拥有的数据的性质?
例如,用户的姓名+密码+年龄+某些东西被用作复合识别符?
在Hibernate中,自然密钥通常用于查找。 在大多数情况下,您将拥有自动生成的代理ID。 但是这个id对于查找来说是无用的,因为你总是会查询名称,社会安全号码或现实世界中的任何其他字段。
使用Hibernate的缓存function时,这种差异非常重要:如果缓存由主键(代理ID)索引,则查找不会有任何性能提升。 这就是为什么您可以定义一组要用数据库查询数据库的字段 – 自然ID。 然后,Hibernate可以通过您的自然键索引数据并提高查找性能。
有关示例Hibernate映射文件的详细说明,请参阅此优秀博客文章或此RedHat页面 。
什么自然地标识一个实体。 例如,我的电子邮件地址。
但是,长可变长度字符串不是理想的键,因此您可能希望定义代理ID
AKA 关键设计中的自然关键
自然标识符是在现实世界中用作标识符的东西。 一个例子是社会安全号码或护照号码。
使用自然标识符作为持久层中的键通常是一个坏主意,因为a)它们可以在您的控件之外进行更改,并且b)由于其他地方的错误,它们最终可能不会是唯一的,然后您的数据模型可以处理它,以便您的应用程序爆炸。
在关系数据库系统中,通常可以使用两种类型的简单标识符 :
- 自然键,由外部系统分配并保证是唯一的
- 代理键,如IDENTITY或SEQUENCE ,由数据库分配。
代理键如此受欢迎的原因是它们更紧凑(4字节或8字节),而自然键非常长(例如,VIN需要17个字母数字字符,书籍ISBN长度为13位)。
现在,如果代理键成为主键,则使用JPA @Id
注释使其成为主键。
并且,如果你有一个也有自然键的实体,除了Surrogate之外,你可以用Hibernate特定的@NaturalId
注释映射它 :
@Entity(name = "Post") @Table(name = "post") public class Post { @Id @GeneratedValue private Long id; private String title; @NaturalId @Column(nullable = false, unique = true) private String slug; //Getters and setters omitted for brevity @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Post post = (Post) o; return Objects.equals(slug, post.slug); } @Override public int hashCode() { return Objects.hash(slug); } }
现在,考虑到上面的实体,用户可能已经为Post
文章添加了书签,现在他们想要阅读它。 但是,带书签的URL包含slug
Natural Identifier,而不是主键。
所以,我们可以使用Hibernate这样获取它:
Post post = entityManager.unwrap(Session.class) .bySimpleNaturalId(Post.class) .load(slug);
Hibernate将执行以下两个查询:
SELECT p.id AS id1_0_ FROM post p WHERE p.slug = 'high-performance-java-persistence' SELECT p.id AS id1_0_0_, p.slug AS slug2_0_0_, p.title AS title3_0_0_ FROM post p WHERE p.id = 1
需要第一个查询来解析与提供的自然标识符相关联的实体标识符。
如果实体已加载到第一级或第二级缓存中,则第二个查询是可选的。
正如我在本文中所解释的那样,获得第一个查询的原因是因为Hibernate已经有了一个完善的逻辑,用于通过持久化上下文中的标识符加载和关联实体。
现在,如果要跳过实体标识符查询,可以使用@NaturalIdCache
批注轻松地注释实体:
@Entity(name = "Post") @Table(name = "post") @org.hibernate.annotations.Cache( usage = CacheConcurrencyStrategy.READ_WRITE ) @NaturalIdCache public class Post { @Id @GeneratedValue private Long id; private String title; @NaturalId @Column(nullable = false, unique = true) private String slug; //Getters and setters omitted for brevity @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Post post = (Post) o; return Objects.equals(slug, post.slug); } @Override public int hashCode() { return Objects.hash(slug); } }
这样,您甚至可以在不访问数据库的情况下获取Post
实体。 很酷,对吗?
社会安全号码可能是自然身份 ,或者您已经说过用户信息的哈希值。 替代方案是代理键 ,例如Guid / UID。
自然标识符 (也称为业务密钥):是指在现实生活中表示或表示某事物的标识符。
电子邮件或国家身份certificate
Isbn for Book
IBAN 银行账户
此@NaturalId
注释用于指定自然标识符。
- 如何使用Hibernate / JPA2实现Spring Security用户/权限?
- HIbernate无法使用外键删除实体。 外键设置为null
- 使用Hibernate将下拉列表值保存到Struts 2中的数据库
- 没有可用于当前线程的实际事务的EntityManager – 无法可靠地处理“刷新”调用
- 是什么导致org.hibernate.PropertyAccessException:setter中发生exception
- 如何在复合键中使用生成的值?
- org.hibernate.HibernateException:无法实例化默认tuplizer
- 由于Bean Validation API而无法启动Hibernate Validator
- Hibernate:设置默认查询超时?