Affects: \5.3.20 org.springframework : spring-aop 5.3.20 spring-orm 5.3.18


I have one entity Parent that holds a set of child entities, what I do is - pulling the parent entity from DB - add a child entity to the set (no id value) - call getSessionFactory().getCurrentSession().lock(entity, LockMode.OPTIMISTIC); - then the exception get thrown

It would work and insert/update the parent and child if I call update. Also changing a non-collection property (String) will work with the LOCK. only the LOCK and a collection get failed.

I don't understand the check for isDirty() in OnLockVisitor line 47, why do we care if the collection is dirty, we don't check that when the String is dirty. Is there a way around it?

parent entity


@Entity
@Table(name = "tenant_users")
public class TenantUser {
 @Id
  @SequenceGenerator(name = "tenant_users_id_seq", allocationSize = 1)
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tenant_users_id_seq")
  @Column(name = "id")
  private Long id;

  @OneToMany(fetch = FetchType.EAGER, mappedBy = "tenantUser", cascade = CascadeType.ALL, orphanRemoval = true)
  @Where(clause = "is_deleted is false")
  @JsonManagedReference
  @OptimisticLock(excluded = true)
  private Set<TenantUserBusinessUnit> businessUnits = new HashSet<>();

  @Version
  @Column(name = "version")
  private LocalDateTime version;
}

child entity


@Entity
@Table(name = "tenant_user_business_units")
public class TenantUserBusinessUnit

  @Id
  @SequenceGenerator(name = "tenant_user_business_units_id_seq", allocationSize = 1)
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tenant_user_business_units_id_seq")
  @Column(name = "id")
  private Long id;

  @JsonIdentityInfo(generator = ObjectIdGenerators.UUIDGenerator.class, property = "id")
  @ManyToOne(optional = false)
  @JoinColumn(name = "tenant_user_id")
  @JsonBackReference
  private TenantUser tenantUser;

Exception Stack trace:

org.hibernate.HibernateException: re-associated object has dirty collection
    at org.hibernate.event.internal.OnLockVisitor.processCollection(OnLockVisitor.java:48)
    at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:104)
    at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:65)
    at org.hibernate.event.internal.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:59)
    at org.hibernate.event.internal.AbstractVisitor.process(AbstractVisitor.java:126)
    at org.hibernate.event.internal.AbstractReassociateEventListener.reassociate(AbstractReassociateEventListener.java:84)
    at org.hibernate.event.internal.DefaultLockEventListener.onLock(DefaultLockEventListener.java:79)
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107)
    at org.hibernate.internal.SessionImpl.fireLock(SessionImpl.java:745)
    at org.hibernate.internal.SessionImpl.lock(SessionImpl.java:731)

Comment From: jhoeller

As far as I can see, there is nothing specific to Spring here. Please report this issue to the Hibernate project instead.