hibernate_Hibernate中的自然身份证

hibernate

hibernate

自然ID是可以唯一标识实体的一个或一组属性。 我们最多可以为一个实体定义一个自然ID。 当Hibernate在实体映射文件中看到natural-id标记时,它会自动在构成natural-id的属性上创建唯一且非空的约束。 首先,让我们看一下简单和复合自然ID的示例。

简单的自然ID:一个人可以通过其选民ID进行唯一标识。 因此,我们可以说这可能来自他的自然身份。

<!-- Version 1 -->
<hibernate-mapping package="com.pramati.model">
	<class name="Person" table="PERSON">
		<id name="id" column="ID">
			<generator class="native"/>
		</id>
		<natural-id>
			<property name="voterId" type="string" column="VOTER_ID"/>
		</natural-id>
		<property name="name" type="string" column="NAME"/>
		<!-- Other properties -->
</class>
</hibernate-mapping>

复合自然ID:电话号码,即标准代码和固定电话号码的组合,可以形成个人实体的自然ID。

<!-- Version 2 -->
<hibernate-mapping package="com.pramati.model">
	<class name="Person" table="PERSON">
		<id name="id" column="ID">
			<generator class="native"/>
		</id>
		<natural-id>
			<property name="stdCode" type="string" column="STD_CODE"/>
			<property name="landlineNumber" type="string" column="LANDLINE_NUMBER"/>
		</natural-id>
		<property name="name" type="string" column="NAME"/>
		<!-- Other properties -->
</class>
</hibernate-mapping>

因此,Hibernate在stdCode和landlineNumber上创建了一个非空约束。 这些属性对于个人实体应该是唯一的。

默认情况下,自然ID是不可变的。 因此,假设如果您尝试从数据库中加载人员实体并更改构成自然ID的任何属性,则Hibernate将引发异常。 例如,我们已经加载Person并尝试在活动会话中修改其landlineNumber / stdcode,这是我们会得到的例外:

org.hibernate.HibernateException:: An immutable natural identifier 
of entity com.pramati.model.Person was altered from abc to xyz

Hibernate 4.1提出了通过bean的natural-id加载实体的功能。 到目前为止,会话缓存将缓存通过当前会话中的get / load加载的对象。 现在,默认情况下还将缓存使用natural-id加载的对象。 以下是会话API的最新功能:

public NaturalIdLoadAccess byNaturalId(String entityName);
public NaturalIdLoadAccess byNaturalId(Class entityClass);

public SimpleNaturalIdLoadAccess bySimpleNaturalId(String entityName);
public SimpleNaturalIdLoadAccess bySimpleNaturalId(Class entityClass);

我们可以通过自然ID加载类的实例,如下所示:

// In case of version 1 defined above:
Person person = (Person)session.byNaturalId(Person.class )
				.using( "voterID", "ZAAXDFT435" )
				.load();

// For Version 1, this can be simplified as:
Person person = (Person)session.bySimpleNaturalId(Person.class )
				.load("ZAAXDFT435");

// In case of version 2 defined above:
Person person = (Person)session.byNaturalId(Person.class )
				.using("stdCode", "040")
				.using("landlineNumber","2345678")
				.load();

请注意,负载返回的实体不仅是代理,而且是实际实体本身。 如果要获取代理,则必须使用getReference()代替load(),如下所示:

session.byNaturalId(Person.class )
.using("stdCode", "040")
.using("landlineNumber","2345678")
.getReference();

为了保持一致性,新方法也可用于基于标识符的加载。

public IdentifierLoadAccess byId(String entityName);
public IdentifierLoadAccess byId(Class entityClass);

因此,我们可以使用session.byId(Person.class).getReference(id)代替session.load(Person.class,id)。 而不是session.get(Person.class,id)我们可以使用session.byId(Person.class).load(id)

当我们使用查询缓存时,自然ID也很有用。 查询缓存通常没有那么有用,因为它经常变得无效。 假设事件序列如下:

方案1:

1.使用实体natural-id中的属性进行HQL查询以加载人员A。 查询也被缓存,即query.setCacheable(true)2.将另一个人B插入到人表中。3.现在,使用与步骤1中相同的查询再次加载A。问题是:在步骤3中,将执行新的数据库调用以从“人”表中获取A。 是还是不是?

答案是肯定的。 发生的事情是Hibernate在内部维护一个时间戳缓存。 该时间戳缓存记录特定Hibernate受管表被修改的时间。 现在在步骤(3),Hibernate看到它是一个缓存的查询。 但是,在返回存在于缓存中的实体之前,它会验证缓存的结果相对于表修改时间是否较旧。 现在,由于在缓存后修改了表,因此Hibernate再次进行了新查询。

为了进一步了解这一点,让我们考虑以下情形:让我们只在名称为Rama的Person表中进行记录

方案2:

一种。 执行缓存的查询以获取名称匹配“ Rama”的人员列表:“来自人员名称='Rama'的人员”b。 也将记录插入名称也为“ Rama”的“个人”中。 这不是问题,因为名称未定义为唯一属性C。 现在,再次执行步骤(a)中的查询。

最初在步骤(a),我们仅获得记录。 但是在步骤(c)中,即使结果被缓存,Hibernate也会再次命中数据库。 这是由于时间戳缓存无效而发生的。 Hibernate只是在从缓存返回实体之前检查表是否已被修改。 但是,无论是更新,插入还是后续操作,都不会影响表的更新方式。

但在我们看过的前一种情况中,此验证检查似乎完全不相关,因为插入的记录与加载的实体无关。 如果我们使用自然ID来获取实体,则可以绕过此检查。 使用natural-id时,可以保证即使修改数据库后结果也不会改变。 早些时候,当我们不支持使用自然ID加载实体时,我们在Criteria API中提供了使用自然ID的规定。 我们可以在方案1的步骤(1)和(3)中使用以下内容

session.createCriteria(Person.class).add(
		Restrictions.naturalId().set("stdCode", person.getStdCode()).
		set("landlineNumber", person.getLandlineNumber())).
		setCacheable(true).
		uniqueResult();

当使用自然ID来获取实体时,时间戳缓存检查将被绕过。 因此,现在,如果我用此条件而不是查询替换第一种情况的步骤(1)和(3),则数据库只会被命中一次。 如果我们使用Restrictions.eq而不是Restrictions.naturalId,则数据库将被命中两次。 另外,如果您使用的是最新版本的Hibernate,我们可以使用新的API代替构建标准。

参考:prasanthnath博客上来自JCG合作伙伴Prasanth G的“Hibernate中的自然ID”

翻译自: https://www.javacodegeeks.com/2013/10/natural-ids-in-hibernate.html

hibernate

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值