HHH000444 warning, follow on locking (appears after migration to Spring Boot 3)

After migrating from Spring Boot 2.7 to Spring Boot 3, this warning appears in the logs when executing a query with lock:

"HHH000444: Encountered request for locking however dialect reports that database prefers locking be done in a separate select (follow-on locking); results will be locked after initial query executes"

I checked the Hibernate version, which also changed during the migration

before migration: org.hibernate:hibernate-core:5.6.15.Final.

after migration: org.hibernate.orm:hibernate-core:6.2.13.Final.

Here are sample queries I have, there are several and they all look quite similar to these:

    @Transactional(propagation = Propagation.MANDATORY)
    @Lock(LockModType.PESSIMISTIC_WRITE)
    @Query("SELECT n FROM #{#name} n WHERE n.id = ?1")
    T findById(UUID id);
    @Transactional(propagation = Propagation.MANDATORY)
    @Lock(LockModeType.PESSIMISTIC_READ)
    boolean IsExists(K id);

I also tried to force this warning to be disabled with query hints by adding such an annotation to methods:
@QueryHints(value = { @QueryHint(name = "hibernate.query.followOnLocking", value = "false") }, forCounting = false)

But that didn’t help either, and the warning still appears. (I am using a PostgreSQL database)

I read an article about this error: HHH000444 warning, follow on locking

And they write that in version 6.2.3.Final there was a bug that caused follow-on locking and it has been fixed, however this kind of warning appears and I don’t know what the bug really means and why it appeared.

Thank you in advance for help.

It is possible that you’re seeing this warning if you’re using an entity-graph for the query that causes a left join to be created in the SQL. Since for update locking doesn’t work in PostgreSQL when using left joins, Hibernate ORM will use follow-on locking and hence emit this warning.
Another possible reason for left joins to be generated is that you’re fetching an entity that has an association which is a @OneToOne(mappedBy = "...") or a @XToOne with @NotFound.

Show the HQL queries that Spring generates and passes to Hibernate ORM as well as the SQL queries that are generated by Hibernate ORM.

Thanks for the reply,

Since for update locking doesn’t work in PostgreSQL when using left joins, Hibernate ORM will use follow-on locking and hence emit this warning.

Referring to this, has this always been the case in Hibernate, or was it only introduced in version 6? Well, since I didn’t get any warning in version 5 (so what could have really changed in the new version (?))

Hmm, that doesn’t really make sense. Can you please try to create a reproducer with our test case template (https://github.com/hibernate/hibernate-test-case-templates/blob/master/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java) and if you are able to reproduce the issue, create a bug ticket in our issue tracker(https://hibernate.atlassian.net) and attach that reproducer.

Hi @beikov we are using hibernate-core:6.4.1.Final and postgresql DB, we have an entity A which have @ManyToOne association with entity B (without @NotFound). We still are facing this warning and the sql generated is left join. Now what is happening that we are facing lost update concurrency problem. The transactions are using jakarta.persistence.EntityManager#find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) with PESSIMISTIC_WRITE lock.

Below is the sql trace -
==== txn 1 =====

2024-02-06 01:19:37.554 [ThreadPoolTaskExecutor-2] [] WARN  - org.hibernate.sql.results.jdbc.internal.DeferredResultSetAccess HHH000444: Encountered request for locking however dialect reports that database prefers locking be done in a separate select (follow-on locking); results will be locked after initial query executes 
Hibernate: 
    select
        a1_0.a_id,
        a1_0.b_id,
        b1_0.b_id,
        b1_0.name,
        b1_0.status,
        a1_0.dummy_col 
    from
        entity_a a1_0 
    left join
        entity_b b1_0 
            on b1_0.b_id=a1_0.b_id 
    where
        a1_0.a_id=?
Hibernate: 
    select
        b_id 
    from
        entity_b 
    where
        b_id=? for update
Hibernate: 
    select
        a_id 
    from
        entity_a 
    where
        a_id=? for update

==== txn 2 ====

Hibernate: 
    select
        a1_0.a_id,
        a1_0.b_id,
        b1_0.b_id,
        b1_0.name,
        b1_0.status,
        a1_0.dummy_col 
    from
        entity_a a1_0 
    left join
        entity_b b1_0 
            on b1_0.b_id=a1_0.b_id 
    where
        a1_0.a_id=?
Hibernate: 
    select
        b_id 
    from
        entity_b 
    where
        b_id=? for update

Both txns are using same method, however txn2 hangs (after step over through EntityManger.find()) with these 2 sql queries when txn1 has already taken lock on the row. After txn1 commits, txn2 fires

Hibernate: 
    select
        a_id 
    from
        entity_a 
    where
        a_id=? for update

Lost updates weren’t there in hibernate 5.6.15.Final which we were using ealier, neither this warning.
Many thanks for any help

Please create a reproducer based on our test case template and share that.