使用hibernate @Version控件进行DTO实体映射

时间:2013-09-11 01:59:13

标签: java hibernate jpa

我正在使用@Version注释在hibernate中提供版本控制。我的问题是关于从DTO到Entity的数据的正确映射。 我觉得正确的方法如下,但我想知道是否有更好的方法,或者每个人都这样做。

  • 来电我的服务
  • 我加载要更新的实体(假设AddressEntity版本= 1)
  • 我将AddressDTO值映射到AE,包括子集(如果有的话)
  • 在所有映射之后,我分离实体AE(仅在Lazy子集合映射之后才被分离)
  • 现在我将版本从DTO映射到AE(因为hibernate不允许更新托管实体中的版本)
  • 现在我调用merge来更新这个独立的AE实体

1)这是正确的语义和逻辑方式吗?

2)(比特超出上下文)是否存在hibernate合并已经在上下文和托管中的对象的开销,即我可以安全地使用合并来安全地进行所有更新,无论是管理/非托管还是仅针对非托管和flush进行合并+刷新更新一些属性后管理?

2 个答案:

答案 0 :(得分:2)

让我试着逐步回答你的问题:

  1. 假设您已加载AddressEntity (having id=123 and version=1)。将属性值从AddressEntity设置为AddreeDto,包括idversion值。将AddressDto发送给用户界面。
  2. AddresDto所做的更改。电话已经来到您的服务。创建AddressEntity的实例,并设置AddressDto的值,包括idversion值。这个新的AddressEntity现在变成了一个分离的实例,因为它具有持久性标识,但不保证其状态与数据库状态同步。
  3. Hibernate允许您通过重新关联新的持久性管理器,在新事务中重用此Addressentity实例。可以通过调用update()将此分离实例与新会话重新关联。您不需要再次加载实体.upcate()方法强制更新数据库中对象的持久状态。

    设置addressEntity属性:

    addressEntity.setId(dto.getId()); addressEntity.setVersion(dto.getVersion());

    addressEntity附加到新会话:

    交易tx = sessionTwo.beginTransaction(); sessionTwo.update(addressEntity);

    tx.commit(); sessionTwo.close();

  4. session.update将执行类似于此的SQL:

    更新ADDRESS_ENTITY set ...,VERSION = 2 其中ID = 123且VERSION = 1

  5. 如果另一个应用程序事务在加载后更新了相同的ADDRESS_ENTITY,则VERSION列将不包含值1,并且该行将不会更新,您将收到stale object state exception。您可以捕获异常并通知用户有关陈旧数据的信息。

答案 1 :(得分:0)

  
      
  • 在所有映射之后,我分离实体AE(仅在Lazy子集合映射之后才被分离)
  •   

假设您在单个交易中执行此操作。您从DB检索的任何持久对象都与当前会话和事务上下文相关联。如果在同一事务中修改它,其状态将自动与DB同步。此机制称为automatic dirty checking。这意味着Hibernate将跟踪并保存对会话内对象所做的更改。

Transaction tx = session.beginTransaction();
int addressEntityID = 1234;
AddressEntity addressEntity = (AddressEntity) session.get(AddressEntity.class, new Long(addressEntityID));

// set the values from AddressDTO to AddressEntity
tx.commit();
session.close();

从DB检索对象,对其进行修改,并在事务提交时将修改传播到DB。您无需分离并重新附加实体以执行更新。

  
      
  • 现在我将版本从DTO映射到AE(因为hibernate不允许更新托管实体中的版本)
  •   

托管版本控制用于实现乐观锁定,实体的版本控制由Hibernate管理。版本号只是一个计数器值,它没有您应该在DTO中保留的任何有用信息。您不需要自己设置版本的值。 Hibernate将在您第一次保存AddressEntity时初始化该值,并在修改对象时递增或重置它。

如果另一个应用程序事务(T2)将持久化实例更新为当前应用程序事务(T1)读取的相同项目,则T2事务将更改此实体的版本值。现在,当T1尝试进行更新时,Hibernate将抛出stale object state exception,因为实体的version已被更改。您可以捕获exception并告知用户有关陈旧数据的信息。特别是,版本控制可以防止丢失更新问题。您不需要将版本从DTO映射到AE或从AE映射到DTO,因为它没有任何有意义的信息可以在上下文中使用,而不是实现乐观锁定。