Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release connection after transaction if using Hibernate and open-in-view is on (turned off by default) #34138

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

poxu
Copy link

@poxu poxu commented Dec 22, 2024

One of the issues with open-in-view is that connections are not released for a long time, which can lead to connection pool starvation.

Sometimes, controller method even makes no queries for seconds and doesn't really need to keep the connection for itself all that time. For example that is often the case, when application makes REST call after making database query.

This pull request gives user setting, which tells transaction manager, that it should release JDBC connection after transaction is finished (successfully or not). Connection release only happens if the setting is turned on and if open-in-view is enabled. If open-in-view is disabled, then entity manager is closed after transaction is finished and connection is released anyway.

What this pull request changes in existing behaviour

  1. JpaDialect#releaseJdbcConnection is now only called if entity manager is pre-bound. This happens if open-in-view is turned on.
  2. JpaDialect#cleanupTransaction is now called before JpaDialect#releaseJdbcConnection ,
    because if connection is released, transaction manager can't reset isolation level and read-only flag. I think the only reason nobody noticed that before is that nobody tried to override JpaDialect#releaseJdbcConnection for HibernateJpaDialect

What this pull request adds

  1. releaseConnectionAfterTransaction setting for HibernateJpaDialect and which user can configure through HibernateJpaVendorAdapter (like showSql and generateDdl).
  2. HibernateJpaDialect#releaseJdbcConnection method now really releases JDBC connection if releaseConnectionAfterTransaction setting is enabled.

P. S. I think those changes are ok, because the behaviour is copied from HibernateTransactionManager. Hibernate 6 is officially only supported through JpaTransactionManager, so it would be nice to port this HibernateTransactionManager feature.

poxu added 5 commits December 22, 2024 15:28
Even though those two actions trigger under the same condition, they don't have
to be executed in one uninterrupted block of code. Connection only can be
released if connection holder was successfully removed, but that's all
Releasing connection before transaction cleanup may break connection reset.
It certainly does in case of Hibernate, because HibernateJpaDialect needs
active connection to reset isolation level and read only flag.

New unit test simply makes sure cleanup and connection release happen in
expected order.
In case of pre-bound entity manager it makes sense to release connection
after transaction (in some cases at least).

But if entity manager is not pre-bound, then it is going to be closed
immediately after transaction cleanup. And that releases the connection.
So there's no point in releasing the connection manually, if it's
going to be released next moment anyway.
…f open-in-view

This commit introduces a new setting - releaseConnectionAfterTransaction, which
controls if HibernateJpaDialect#releaseJdbcConnection will release connections
when called. ReleaseJdbcConnection method is only called if session is pre-bound,
so the new setting actually doesn't do anything unless open-in-view is on.

And in case if open-in-view is on, turning releaseConnectionAfterTransaction on
might help with connection pool starvation.
…Adapter

Users don't create HibernateJpaDialect themselves, HibernateJpaVendorAdapter
does that. So, this change is needed so that releaseConnectionAfterTransaction
could be configured via application settings.
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Dec 22, 2024
Copy link

@mipo256 mipo256 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, in general, it makes sense to separate a single commit in this PR onto two separate. Both, I think, make sense.

* handling mode without sacrificing setting non-default isolation levels
* or read-only flag. Releasing connection might prevent connection pool
* starvation if open-in-view is on.
* <p> Default is "false" for backward compatibility. If you turn this flag
Copy link

@mipo256 mipo256 Jan 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think this

If you turn this flag on it still does nothing unless session is not pre-bound (most likely if open-in-view) is off

can be simplified to:

This flag only takes effect in case the underlying {@link EntityManager} is pre-bound

* starvation if open-in-view is on.
* <p> Default is "false" for backward compatibility. If you turn this flag
* on it still does nothing unless session is pre-bound (most likely if
* open-in-view) is off. If session is pre-bound and the flag is on, then
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it is perfectly sufficient to say the following:

If session is pre-bound and the flag is on, then after transaction is finished (successfully or not), underlying JDBC connection will be released and acquired later according to {@link org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode}.

* (is set to {@link org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode#DELAYED_ACQUISITION_AND_HOLD}
* with {@link HibernateJpaVendorAdapter#getJpaPropertyMap()} if you don't
* specify it yourself).
* <p> Please pay attention, that this setting doesn't affect how Hibernate
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* <p> Please pay attention, that this setting doesn't affect how Hibernate
* handles connections, which were acquired on-demand, to lazily load
* collections outside of transaction context.
* <p> Specifically, connections, acquired to serialize entities, returned
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand this sentence and its purpose. What connections "acquired to serialize entities" are you talking about here?

Specifically, connections, acquired to serialize entities, returned by rest controller method will only be closed, after serialization is complete. Hibernate will not acquire and release connections for each lazy field loading.

* complete. Hibernate will not acquire and release connections for each
* lazy field loading.
*/
public void setReleaseConnectionAfterTransaction(boolean releaseConnectionAfterTransaction) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can just link the existing releaseConnectionAfterTransaction documentation via javadoc tag @link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: waiting-for-triage An issue we've not yet triaged or decided on
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants