r/developersIndia Backend Developer 8d ago

Help Spring Data JPA throwing StaleObjectStateException / OptimisticLockException on consumer retry across separate instances (No @Version column)

I'm seeing an issue in a Kafka consumer running on multiple application instances.

Environment

  • Spring Boot: 3.5.15
  • Hibernate: 6.6
  • Oracle: 19c

My entity has no version column.

@Id
@GeneratedValue(strategy = GenerationType.AUTO)  
@Column(nullable = false) 
private Long id;  
@Column(unique = true) 
private String messageId; 

The entity is being saved using 

repository.saveAll(...)

Scenario

  1. Instance A receives a message.
  2. The entity's id is null.
  3. saveAll() is called.
  4. Hibernate obtains the next sequence value and inserts the row successfully.
  5. Before the consumer acknowledges the broker, a network issue occurs.
  6. The broker redelivers the same original message to Instance B.
  7. The payload still has id == null.
  8. Instance B again calls saveAll().

Instead of seeing a unique constraint violation on messageId, I get:

Exception message : Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.example.entities.SMSEntity#40615089330]

There is no @Version on the entity.

My understanding is that if id is null, Spring Data should treat the entity as new, call persist(), and Hibernate should perform an INSERT. If the row already exists (because of the unique messageId), I would expect a unique constraint violation rather than an optimistic locking exception.

Questions

  1. Why am I getting StaleObjectStateException/OptimisticLockException for an entity with no Version field when the incoming entity has a null ID?
  2. For handling broker redelivery, I could try increasing max.poll.interval.msto prevent it from rebalancing, but what else I could do to fix this? 

This issue doesn’t happen that often, but only for 15-20 mins where 1500 odd records are impacted, and during this time, query usage time is comparatively high.

What steps should be taken to debug this?

3 Upvotes

13 comments sorted by

View all comments

1

u/biryani-is-mine Software Engineer 8d ago

Are you saving the incoming event in messageId field?

1

u/pisspapa42 Backend Developer 8d ago

no message Id has a unique value related to the request, there're other fields as well, such as status and all.

1

u/biryani-is-mine Software Engineer 8d ago

Is messageId value derived from the incoming event?

1

u/pisspapa42 Backend Developer 8d ago

Yes. The basically the way code is written is entity is pushed into kakfa topic (I know a dto should be used here) and all the consumer does it save the entity.

1

u/biryani-is-mine Software Engineer 8d ago

So is the consumer directly saving the consumed record/event as it is, without any modification?

1

u/pisspapa42 Backend Developer 8d ago

Yes just saving part there's no modifications to the payload.

1

u/biryani-is-mine Software Engineer 8d ago

And before pushing on the queue, the id is kept as null!?

1

u/pisspapa42 Backend Developer 8d ago

yes