JPA @Version行为 [英] JPA @Version behaviour

查看:90
本文介绍了JPA @Version行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用JPA2和Hibernate 3.6.x



我已经对@Version做了一个简单的测试。



假设我们有2个实体,


  1. 实体团队有一个玩家实体列表,双向关系,lazy fetchtype,cascade-type All

  2. 这两个实体都有@Version

以下是情景: b
$ b


  1. 每当对团队/球员实体进行修改时,团队/球员的版本将在刷新/提交时增加修改后的记录会增加)。

  2. 使用persist将新玩家实体添加到团队的集合中,团队版本的实体将在持久后分配(添加新实体,新实体将获得它的版本)。
  3. 无论何时对其中一个玩家实体进行添加/修改/移除,该团队的版本将会增加刷新/提交时。 (添加/修改/删除子记录,父母的版本也增加)


我可以理解数字1和2 ,但数字3,我不明白,为什么球队的版本有所增加?



这让我想到其他问题:


  1. 如果我得到Parent<> child<> granchildren关系船,该怎么办?对子孙的增加或修改是否会增加孩子和父母的版本?

  2. 在情景2中,如何在团队提交之前获取版本,例如使用flush ?在我们对孩子做些什么之后,是否推荐使用父母的版本?






以下是我的实验中的代码示例,证明当ReceivingGoodDetail为拥有者时,在冲洗后ReceivingGood中的版本增加。对不起,这使用其他实体,但ReceivingGood就像团队,ReceivingGoodDetail就像播放器。 1 ReceivingGood / Team,许多ReceivingGoodDetail / Player。

  / * 
Hibernate:selectg0_.id as id9_14_,receivingg0_ .creationDate as creation2_9_14_,.. too long
Hibernate:select product0_.id as id0_4_,product0_.creationDate as creation2_0_4_,.. too long
在持续新的细节之前,标题版本是:14
坚持细节1c9f81e1-8a49-4189-83f5-4484508e71a7
打印头的大小:
Hibernate:选择details0_.receivinggood_id作为receivi13_9_8_,details0_.id作为id8_,details0_.id作为id10_7_, ..太久
7
在持续新的细节之后,标题的版本是:14
Hibernate:插入ReceivingGoodDetail(creationDate,modificationDate,usercreate_id,usermodify_id,version,buyQuantity,buyUnit,internalQuantity ,internalUnit,product_id,receivinggood_id,supplierLotNumber,id)值(?,?,?,?,?,?,?,?,?,?,?,?)
Hibernate:update ReceivingGood set creationDate = ?,修改cationDate = ?, usercreate_id =?,usermodify_id =?,version =?,purchaseorder_id =?,supplier_id =?,transactionDate = ?, transactionNumber =?,transactionType = ?, transactionYearMonth =?,warehouse_id =?其中id =?和版本=?
在刷新后,标题的版本现在是:15
* /
public void addDetailWithoutTouchingCollection(){
String headerId =3b373f6a-9cd1-4c9c-9d46-240de37f6b0f;
ReceivingGood receivingGood = em.find(ReceivingGood.class,headerId);

//创建一个新的细节
ReceivingGoodDetail receivingGoodDetailCumi = new ReceivingGoodDetail();
receivingGoodDetailCumi.setBuyUnit(Drum);
receivedGoodDetailCumi.setBuyQuantity(1L);
receivingGoodDetailCumi.setInternalUnit(Liter);
receivingGoodDetailCumi.setInternalQuantity(10L);
receivingGoodDetailCumi.setProduct(getProduct(b3e83b2c-d27b-4572-bf8d-ac32f6de5eaa));
receivedGoodDetailCumi.setSupplierLotNumber(供应商批号1);
decorateEntity(receivingGoodDetailCumi,getUser(3978fee3-9690-4377-84bd-9fb05928a6fc));
receivedGoodDetailCumi.setReceivingGood(receivingGood);

System.out.println(在持久化新细节之前,标题版本是:+ receivingGood.getVersion());

//坚持它
System.out.println(坚持细节+ receivingGoodDetailCumi.getId());
em.persist(receivingGoodDetailCumi);

System.out.println(打印头的大小:);
System.out.println(receivingGood.getDetails()。size());

System.out.println(在持续新的细节之后,标题的版本是:+ receivingGood.getVersion());

em.flush();

System.out.println(冲洗后,标题版本现在是:+ receivingGood.getVersion());


解决方案

Hibernate。



JPA规范说明:
$ b


所有非关系字段和属性并且该实体拥有的所有关系在版本检查中都包含

然而,Hibernate也会在非版本更改后增加版本, (但是,例如,EclipseLink不会这样做)。此行为可以通过在属性上设置 @OptimisticLock(exclude = true)来禁用。



请注意,适用于关系属性本身的变化,而不适用于所引用对象状态的变化,因此父母版本不会因收集孙辈而发生变化。


im using JPA2 with Hibernate 3.6.x

I have made a simple testing on the @Version.

Let's say we have 2 entities,

  1. Entity Team has a List of Player Entities, bidirectional relationship, lazy fetchtype, cascade-type All
  2. Both entities have @Version

And here are the scenarios :

  1. Whenever a modification is made to one of the team/player entity, the team/player's version will be increased when flushed/commited (version on the modified record is increased).

  2. Adding a new player entity to team's collection using persist, the entity the team's version will be assigned after persist (adding a new entity, that new entity will got it's version).

  3. Whenever an addition/modification/removal is made to one of the player entity, the team's version will be increased when flushed/commited. (add/modify/remove child record, parent's version got increased also)

I can understand the number 1 and 2, but the number 3, i dont understand, why the team's version got increased ?

And that makes me think of other questions :

  1. What if i got Parent <-> child <-> granchildren relation ship. Will an addition or modification on the grandchildren increase the version of child and parent ?
  2. In scenario number 2, how can i get the version on the team before it's commited, like perhaps by using flush ? Is it a recommended way to get the parent's version after we do something to the child[s] ?


Here's a code sample from my experiment, proving that when ReceivingGoodDetail is the owning side, and the version got increased in the ReceivingGood after flushing. Sorry that this use other entities, but ReceivingGood is like the Team, ReceivingGoodDetail is like the Player. 1 ReceivingGood/Team, many ReceivingGoodDetail/Player.

/*
Hibernate: select receivingg0_.id as id9_14_, receivingg0_.creationDate as creation2_9_14_, .. too long
Hibernate: select product0_.id as id0_4_, product0_.creationDate as creation2_0_4_, .. too long
before persisting the new detail, version of header is : 14
persisting the detail 1c9f81e1-8a49-4189-83f5-4484508e71a7
printing the size of the header : 
Hibernate: select details0_.receivinggood_id as receivi13_9_8_, details0_.id as id8_, details0_.id as id10_7_, .. too long
7
after persisting the new detail, version of header is : 14
Hibernate: insert into ReceivingGoodDetail (creationDate, modificationDate, usercreate_id, usermodify_id, version, buyQuantity, buyUnit, internalQuantity, internalUnit, product_id, receivinggood_id, supplierLotNumber, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: update ReceivingGood set creationDate=?, modificationDate=?, usercreate_id=?, usermodify_id=?, version=?, purchaseorder_id=?, supplier_id=?, transactionDate=?, transactionNumber=?, transactionType=?, transactionYearMonth=?, warehouse_id=? where id=? and version=?
after flushing, version of header is now : 15
    */
public void addDetailWithoutTouchingCollection() {
    String headerId = "3b373f6a-9cd1-4c9c-9d46-240de37f6b0f";
    ReceivingGood receivingGood = em.find(ReceivingGood.class, headerId);

    // create a new detail
    ReceivingGoodDetail receivingGoodDetailCumi = new ReceivingGoodDetail();
    receivingGoodDetailCumi.setBuyUnit("Drum");
    receivingGoodDetailCumi.setBuyQuantity(1L);
    receivingGoodDetailCumi.setInternalUnit("Liter");
    receivingGoodDetailCumi.setInternalQuantity(10L);
    receivingGoodDetailCumi.setProduct(getProduct("b3e83b2c-d27b-4572-bf8d-ac32f6de5eaa"));
    receivingGoodDetailCumi.setSupplierLotNumber("Supplier Lot 1");
    decorateEntity(receivingGoodDetailCumi, getUser("3978fee3-9690-4377-84bd-9fb05928a6fc"));
    receivingGoodDetailCumi.setReceivingGood(receivingGood);

    System.out.println("before persisting the new detail, version of header is : " + receivingGood.getVersion());

    // persist it
    System.out.println("persisting the detail " + receivingGoodDetailCumi.getId());
    em.persist(receivingGoodDetailCumi);

    System.out.println("printing the size of the header : ");
    System.out.println(receivingGood.getDetails().size());

    System.out.println("after persisting the new detail, version of header is : " + receivingGood.getVersion());

    em.flush();

    System.out.println("after flushing, version of header is now : " + receivingGood.getVersion());
}

解决方案

It looks like a bug in Hibernate.

JPA Specification says:

All non-relationship fields and properties and all relationships owned by the entity are included in version checks

However, Hibernate also increments version after change of non-owned relationship properties (whereas, for example, EclipseLink doesn't do it). This behaviour can be disabled by setting @OptimisticLock(exclude = true) on the property.

Note that it's only applicable to changes of relationship property itself, not to changes in the state of referenced objects, so that version of parent wouldn't be changes due to changes in collection of grandchildren.

这篇关于JPA @Version行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆