Why is the Hibernate ORM marking a rollback even in the read only state?

I’m using Hibernate 6.1.7 version.
When using queries in @Transactional processed methods, we often encounter an exception. What’s curious is that rollback works the same when using methods annotated with @Transactional (readonly=true).

Of course, I know that in general, we can handle exceptions with the noRollbackFor option. However, when an exception is thrown from the query’s internal behavior, I have no control over the rollback behavior because Hibernate does the rollback marking on its own.

For example, If an exception is thrown in the find() method of org.hibernate.internal.SessionImpl, it bypasses the rollbackOn() method of the RuleBasedTransactionAttribute and marks the rollback a priori as follows.

        } catch (TypeMismatchException | ClassCastException | MappingException var20) {
            throw this.getExceptionConverter().convert(new IllegalArgumentException(var20.getMessage(), var20));

also, the convert() method mark the rollback status like this

    public RuntimeException convert(RuntimeException e) {
        RuntimeException result = e;
        if (e instanceof HibernateException) {
            result = this.convert((HibernateException)e);
        } else {
            this.sharedSessionContract.markForRollbackOnly();
        }

        return result;
    }

In this case, @Transactional will throw an Unexpectedrollbackexception at commit time, regardless of the noRollbackFor option.

This may be the default behavior for DB write operations, but I think it throws unnecessary exceptions for read operations. Is there any way to at least ignore the rollback on reading? Or, is there any way to avoid marking rollback in internal behaviors like find method?

What exceptions are we talking about here? Hibernate has to obey the rules of the JPA specification regarding rollback when exceptions occur and it’s also not easy to maintain a consistent internal state when exceptions happen somewhere during result processing, which is why a session usually should not be used anymore after an exception happens.