-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 
Author Message
 Post subject: OptimisticLockException while persisting an entity
PostPosted: Thu Jan 04, 2018 7:14 pm 
Newbie

Joined: Tue Mar 22, 2016 11:40 am
Posts: 8
We are trying to configure Optimistic Lock in our application and we have annotated a Timestamp attribute of the entity class with @Version. Let’s take two tables Parent & Child to explain this issue. Parent has OneToMany association with Child and Child has ManyToOne association with Parent. We have @Version annotation in both the entities as we need OptimisticLock in both the entities when the respective entity is the primary entity we are trying to persist or update.

Scenario:
Parent record already created in DB through a different business flow. Now we are trying to create a new Child record in DB. To do that, we have created a new instance of Child entity and populated the attributes and set the Parent entity object created just only with the primary key attribute which is the foreign key reference for Child.

When we try to persist new Child1 instance we are getting the below warning and transaction errors out. This error started occurring after we have added @Version annotation in the entity classes. Prior to that the persist was working fine.
2018/01/03 12:47:30,375 WARN [org.hibernate.action.internal.UnresolvedEntityInsertActions] (http-10.47.41.110:15100-5) HHH000437: Attempting to save one or more entities that have a non-nullable association with an unsaved transient entity. The unsaved transient entity must be saved in an operation prior to saving these dependent entities.

We did a work-around by adding nullable = true for association and after that we are getting OptimisticLockException for Parent record.
javax.persistence.OptimisticLockException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.engine.model.Parent1#51726]||com.framework.exception.FatalException: javax.persistence.OptimisticLockException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.engine.model.Parent1#51726]

Is there a way to force Hibernate not to apply OptimisticLock (not to check version) for associated entities, but only for the main entity we are trying to persist or merge. We have tried adding @OptimisticLock (excluded=true) for associations in the entity class, but that didn’t help with this scenario. As per the spec, @OptimisticLock (excluded=true) will avoid incrementing the version of parent when child list getting changed, but it won’t do anything with version check.

Also is there any other way to configure Optimistic Locking in JPA/Hibernate other than @Version annotation.

We are using JPA 2.0/Hibernate 4.2.18.

DAO

Code:
Child child = new Child();
   Parent parent = new Parent();
   parent.setParentId(idOfExistingParent); //Parent with this id already exists in DB
   child.setParent(parent);
   child.setModifyBy(usrSeqId);
   child.setModifyTimstm(currentTime);
    try {
      entityManager.persist(bidlistOffer);
    } catch (PersistenceException persistenceException) {
      log.error(persistenceException.getMessage());
    }


Top
 Profile  
 
 Post subject: Re: OptimisticLockException while persisting an entity
PostPosted: Thu Jan 04, 2018 7:16 pm 
Newbie

Joined: Tue Mar 22, 2016 11:40 am
Posts: 8
Here are the Parent and Child entity classes.

Parent
Code:
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

@Entity
@Table(name = "PARENT", uniqueConstraints = @UniqueConstraint(columnNames = {
    "ASSOC_PARENT_1_ID", "ASSOC_PARENT_2_ID", "ASSOC_PARENT_3_ID" }))
public class FinanceSourceCreditLimit implements java.io.Serializable {

  private long parentId;
  private AssocParent1 assocParent1;
  private AssocParent2 assocParent2;
  private AssocParent3 assocParent3;
  private BigDecimal decColumn1;
  private Set<Child> childSet = new HashSet<>();
  private long modifyById;
  private Timestamp modifyTimstm;

  public Parent() {
    /**
     * Any entity class must define a non-private zero-argument constructor
     */
  }

  public Parent(long parentId,
      AssocParent1 assocParent1, AssocParent2 assocParent2,
      AssocParent3 assocParent3, BigDecimal decColumn1, Set<Child> children,
      long modifyById, Timestamp modifyTimstm) {
    this.parentId = parentId;
    this.assocParent1 = assocParent1;
    this.assocParent2 = assocParent2;
    this.assocParent3 = assocParent3;
    this.decColumn1 = decColumn1;
    this.children = children;
    this.modifyById = modifyById;
    this.modifyTimstm = modifyTimstm;
  }

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ParentIdGenerator")
  @SequenceGenerator(name = "ParentIdGenerator", sequenceName = "SEQ_PARENT", allocationSize = 1)
  @Column(name = "PARENT_ID", unique = true, nullable = false, precision = 10, scale = 0)
  public long getParentId() {
    return this.parentId;
  }

  public void setParentId(long parentId) {
    this.parentId = parentId;
  }

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "ASSOC_PARENT_1_ID", nullable = false)
  public AssocParent1 getAssocParent1() {
    return this.assocParent1;
  }

  public void setCreditLimitType(AssocParent1 assocParent1) {
    this.assocParent1 = assocParent1;
  }

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "ASSOC_PARENT_2_ID")
  public AssocParent2 getAssocParent2() {
    return this.assocParent2;
  }

  public void setAssocParent2(AssocParent2 assocParent2) {
    this.assocParent2 = assocParent2;
  }

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "ASSOC_PARENT_3_ID", nullable = false)
  public AssocParent3 getAssocParent3() {
    return this.assocParent3;
  }

  public void setAssocParent3(AssocParent3 assocParent3) {
    this.assocParent3 = assocParent3;
  }

  @Column(name = "DEC_COL_1", precision = 10)
  public BigDecimal getDecColumn1() {
    return this.decColumn1;
  }

  public void setDecColumn1(BigDecimal decColumn1) {
    this.decColumn1 = decColumn1;
  }

  @OneToMany(fetch = FetchType.LAZY, mappedBy = "parent")
  @OptimisticLock(excluded=true)
  public Set<Child> getChildren() {
    return this.children;
  }

  public void setChildren(Set<Child> children) {
    this.children = children;
  }

  @Column(name = "MODIFY_BY_ID", nullable = false, precision = 10, scale = 0)
  public long getModifyById() {
    return this.modifyById;
  }

  public void setModifyById(long modifyById) {
    this.modifyById = modifyById;
  }

  @Version
  @org.hibernate.annotations.Generated(GenerationTime.ALWAYS)
  @org.hibernate.annotations.Source(SourceType.VM)
  @Column(name = "MODIFY_TIMSTM", nullable = false)
  public Timestamp getModifyTimstm() {
    return this.modifyTimstm;
  }

  public void setModifyTimstm(Timestamp modifyTimstm) {
    this.modifyTimstm = modifyTimstm;
  }

}



Child
Code:
import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Version;

@Entity
@Table(name = "Child")
public class Child implements java.io.Serializable {

  private long                     childId;
  private Parent                parent;
  private long                     modifyBy;
  private Timestamp                modifyTimstm;

  public Child() {
    /**
     * Any entity class must define a non-private zero-argument constructor
     */
  }

  public Child(long childId, Parent parent, long modifyBy, Timestamp modifyTimstm) {
    this.childId = childId;
    this.parent = parent;
    this.modifyBy = modifyBy;
    this.modifyTimstm = modifyTimstm;
  }

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_CHILD")
  @SequenceGenerator(name = "SEQ_CHILD", sequenceName = "SEQ_CHILD", allocationSize = 1)
  @Column(name = "CHILD_ID", unique = true, nullable = false, precision = 10, scale = 0)
  public long getChildId() {
    return this.childId;
  }

  public void setChildId(long childId) {
    this.childId = childId;
  }

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "PARENT_ID", nullable = true) //modified
  //@JoinColumn(name = "PARENT_ID", nullable = false)
  @OptimisticLock(excluded=true)
  public Parent getParent() {
    return this.parent;
  }

  public void setParent(Parent parent) {
    this.parent = parent;
  }

  @Column(name = "MODIFY_BY", nullable = false, precision = 10, scale = 0)
  public long getModifyBy() {
    return this.modifyBy;
  }

  public void setModifyBy(long modifyBy) {
    this.modifyBy = modifyBy;
  }

  @Version
  @org.hibernate.annotations.Generated(GenerationTime.ALWAYS)
  @org.hibernate.annotations.Source(SourceType.VM)
  @Column(name = "MODIFY_TIMSTM", nullable = false)
  public Timestamp getModifyTimstm() {
    return this.modifyTimstm;
  }

  public void setModifyTimstm(Timestamp modifyTimstm) {
    this.modifyTimstm = modifyTimstm;
  }

}


Top
 Profile  
 
 Post subject: Re: OptimisticLockException while persisting an entity
PostPosted: Fri Jan 05, 2018 4:16 am 
Hibernate Team
Hibernate Team

Joined: Thu Sep 11, 2014 2:50 am
Posts: 1630
Location: Romania
Quote:
HHH000437: Attempting to save one or more entities that have a non-nullable association with an unsaved transient entity. The unsaved transient entity must be saved in an operation prior to saving these dependent entities.


This exception has nothing to do with optimistic locking, but with how entity relationships are set. Make sure you always set both sides in a bidirectional association as explained in this article.


Top
 Profile  
 
 Post subject: Re: OptimisticLockException while persisting an entity
PostPosted: Wed Jan 10, 2018 2:27 pm 
Newbie

Joined: Tue Mar 22, 2016 11:40 am
Posts: 8
But I don't see this issue if I don't have @Version annotation in Parent entity's modified_timestamp column.

Also, I don't see the same issue if I use Hibernate native locking mechanism in Parent entity using @DynamicUpdate and @OptimisticLockType.DIRTY.


Top
 Profile  
 
 Post subject: Re: OptimisticLockException while persisting an entity
PostPosted: Wed Jan 10, 2018 4:16 pm 
Hibernate Team
Hibernate Team

Joined: Thu Sep 11, 2014 2:50 am
Posts: 1630
Location: Romania
Send a replicating test case using our templates:

http://in.relation.to/2016/01/14/hibern ... -template/


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.