# OPTIMISTIC\_FORCE\_INCREMENT does not work on flush()

**URL:** <https://discourse.hibernate.org/t/optimistic-force-increment-does-not-work-on-flush/11661>\
**Category:** Hibernate ORM\
**Created:** [July 19, 2025, 3:57pm UTC](https://discourse.hibernate.org/t/optimistic-force-increment-does-not-work-on-flush/11661 "2025-07-19T15:57:26Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![piodu](https://avatars.discourse-cdn.com/v4/letter/p/54ee81/32.png) [@piodu](https://discourse.hibernate.org/u/piodu)\
**Post date:** [July 19, 2025, 3:57pm UTC](https://discourse.hibernate.org/t/optimistic-force-increment-does-not-work-on-flush/11661/1 "2025-07-19T15:57:26Z")

</div>

Hello,  
I have noticed strange behavior. Although we load an entity with LockType: OPTIMISTIC\_FORCE\_INCREMENT which shall update the version even when there are no changes to entity, when we call flush() this is update is not being triggered.  
Calling isDirty() on session returns also false when no change is made on entity (but FORCE lock present).

When we change a property, then flush() works as expected - entity gets its version updated.

I have created small reproducible example, please checkout the repo and run code:

> **[GitHub - PiotrDuz/hibernate-optimistic-version-lock: Force optimistic lock update does not work when...](https://github.com/PiotrDuz/hibernate-optimistic-version-lock)**
>
> Force optimistic lock update does not work when invoking flush(). Only when property is changed then the version is correctly updated.

stdout logs will show that version is not updated.

Is there something I don’t understand properly?  
Looking forward for a discussion!  
Regards

---

<div class="post-metadata">

**Author:** ![beikov](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/beikov/32/258_2.png) [@beikov](https://discourse.hibernate.org/u/beikov)\
**Post date:** [July 21, 2025, 8:21am UTC](https://discourse.hibernate.org/t/optimistic-force-increment-does-not-work-on-flush/11661/2 "2025-07-21T08:21:34Z")

</div>

The increment happens just before the transaction commits to potentially reduce the time a lock is held on a row to the minimum possible. If you want the increment to happen immediately, use `PESSIMISTIC_FORCE_INCREMENT`.

---

<div class="post-metadata">

**Author:** ![piodu](https://avatars.discourse-cdn.com/v4/letter/p/54ee81/32.png) [@piodu](https://discourse.hibernate.org/u/piodu)\
**Post date:** [July 21, 2025, 8:36am UTC](https://discourse.hibernate.org/t/optimistic-force-increment-does-not-work-on-flush/11661/3 "2025-07-21T08:36:37Z")

</div>

Thank you for answering!  
But is the lock really held? With OPTIMISTIC\_FORCE\_INCREMENT there is no db locking (thus optimistic).  
By issuing PESSIMISTIC LockType there will be select for update, what I want to avoid with optimistic locking.  
Regads

---

<div class="post-metadata">

**Author:** ![beikov](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/beikov/32/258_2.png) [@beikov](https://discourse.hibernate.org/u/beikov)\
**Post date:** [July 21, 2025, 8:50am UTC](https://discourse.hibernate.org/t/optimistic-force-increment-does-not-work-on-flush/11661/4 "2025-07-21T08:50:23Z")

</div>

Like I wrote, the `OPTIMISTIC_FORCE_INCREMENT` lock will be acquired by incrementing the version just right before a transaction commits.

---

<div class="post-metadata">

**Author:** ![piodu](https://avatars.discourse-cdn.com/v4/letter/p/54ee81/32.png) [@piodu](https://discourse.hibernate.org/u/piodu)\
**Post date:** [July 21, 2025, 9:02am UTC](https://discourse.hibernate.org/t/optimistic-force-increment-does-not-work-on-flush/11661/5 "2025-07-21T09:02:09Z")

</div>

Right, but why isnt session marked Dirty then?  
There is a change staged for execution…

---

<div class="post-metadata">

**Author:** ![beikov](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/beikov/32/258_2.png) [@beikov](https://discourse.hibernate.org/u/beikov)\
**Post date:** [July 21, 2025, 9:25am UTC](https://discourse.hibernate.org/t/optimistic-force-increment-does-not-work-on-flush/11661/6 "2025-07-21T09:25:57Z")

</div>

You mean `Session#isDirty` returns `false`? The javadoc of that method say

> In other words, would any DML operations be executed if we flushed this session?

And in fact, the session flushing does not produce any DML statements, so it’s correct. There are of course some pending operations bound to the transaction lifecycle, but `isDirty` is not the method to understand such operations.

Why is that important in the first place?

---

<div class="post-metadata">

**Author:** ![piodu](https://avatars.discourse-cdn.com/v4/letter/p/54ee81/32.png) [@piodu](https://discourse.hibernate.org/u/piodu)\
**Post date:** [July 21, 2025, 9:30am UTC](https://discourse.hibernate.org/t/optimistic-force-increment-does-not-work-on-flush/11661/7 "2025-07-21T09:30:07Z")

</div>

Well, before we use direct jdbc query in transaction, we want to flush() and clear() session to avoid any inconsistences in Hibernate’s L1 cache.  
But this erases the scheduled version increment on locked objects.  
I guess we have to go for manual version increment then

---

<div class="post-metadata">

**Author:** ![beikov](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/beikov/32/258_2.png) [@beikov](https://discourse.hibernate.org/u/beikov)\
**Post date:** [July 21, 2025, 9:48am UTC](https://discourse.hibernate.org/t/optimistic-force-increment-does-not-work-on-flush/11661/8 "2025-07-21T09:48:21Z")

</div>

> we want to flush() and clear() session to avoid any inconsistences in Hibernate’s L1 cache.

I don’t know what “inconsistencies” you’re referring to here, but Hibernate ORM will ensure that the version on the entity is incremented just like it is updated in the database before the transaction commits.

> But this erases the scheduled version increment on locked objects.

I don’t know what that means. Please clarify.

> I guess we have to go for manual version increment then

Like I wrote before, if you want the version increment to happen immediately, then use `PESSIMISTIC_FORCE_INCREMENT`.

---

<div class="post-metadata">

**Author:** ![piodu](https://avatars.discourse-cdn.com/v4/letter/p/54ee81/32.png) [@piodu](https://discourse.hibernate.org/u/piodu)\
**Post date:** [July 21, 2025, 10:08am UTC](https://discourse.hibernate.org/t/optimistic-force-increment-does-not-work-on-flush/11661/9 "2025-07-21T10:08:01Z")

</div>

> [@beikov](#):
>
> I don’t know what “inconsistencies” you’re referring to here,

Generally, when modifying sql is issued outside of hibernate cache, the cache should be cleared so susequent fetches from hibernate do not return stale data.  
Well, even for select queries cache should be flushed at least so db and l1 cache is synchronised.  
This is why we issue flush() clear() before running direct sqls in transaction.

> [@beikov](#):
>
> I don’t know what that means. Please clarify.

I have prepared the reproduction example in my repository just to visualize that. So, in summary:

1. We fetch entity with force optimistic increment lock
2. We then do flush() clear()
3. We comit transaction
4. The version is not updated! It will get updated if we omit flush() clear()

> [@beikov](#):
>
> Like I wrote before, if you want the version increment to happen immediately

Well, it is not about happening immediately but i found it strange that this version update was not making session dirty.  
I can understand that isDirty does return false because the change is bound to happen on transaction commit exclusively. But then, why session clear() is removing this scheduled change?

---

<div class="post-metadata">

**Author:** ![beikov](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/beikov/32/258_2.png) [@beikov](https://discourse.hibernate.org/u/beikov)\
**Post date:** [July 21, 2025, 1:39pm UTC](https://discourse.hibernate.org/t/optimistic-force-increment-does-not-work-on-flush/11661/10 "2025-07-21T13:39:49Z")

</div>

Seems like you’re hitting this known issue: [HHH-13688](https://hibernate.atlassian.net/browse/HHH-13688)

According to the [specification](https://jakarta.ee/specifications/persistence/3.1/jakarta-persistence-spec-3.1#a2100), this behavior is “valid”:

> If an entity is removed before a deferred version update was to have been applied, the forced version update is omitted.

I understand the desire to have this working, but I’m not sure about the best solution. Maybe it would be better to invoke this force increment during flush time, but that might have a negative performance impact for users that flush without clearing.

If this is important to you, I’d suggest you join our [Zulip chat platform](https://hibernate.zulipchat.com/#narrow/stream/132096-hibernate-user) and start a discussion about the topic.

---

<div class="post-metadata">

**Author:** ![piodu](https://avatars.discourse-cdn.com/v4/letter/p/54ee81/32.png) [@piodu](https://discourse.hibernate.org/u/piodu)\
**Post date:** [July 21, 2025, 8:06pm UTC](https://discourse.hibernate.org/t/optimistic-force-increment-does-not-work-on-flush/11661/11 "2025-07-21T20:06:21Z")

</div>

Thabks for explanation.  
I think people may expect that clear() and isdirty() are somewgat synced. So if we say that session is not dirty, then clear does not affect much (whn it comes to losing information).

As I am using spring i am able to simulate wanted behaviour: in those places where forced lock is required, i am registering a TransactionSynchronisation which will apply version increment beforeCommit.

Thanks to our doscussion I’vr understood the problem and think that my proposed workaround is enough for now 😉
