Why is hibernate.connection.release_mode after_transaction not recommended for JTA?
Asked Answered
O

2

13

While analyzing some performance problems in Wildfly 10.1 in high pressure scenarios I came to the conclusion, that sometimes parallel HTTP threads block each other.

The reason seemed to be that in some HTTP requests we execute two JPQL Queries (actually a delete and a select) and sometimes the second of the two simply didn't get a JDBC connection from the pool. (We use IBM DB2, if that is important...) That seemed rather ridiculous as the first statement already got a connection.

After reading the Hibernate docs, I see that the default for hibernate.connection.release_mode is after_statement and that after_transaction is not recommended for JTA apps...

So... I have a few questions now:

  • Why does after_statement ever make sense? (unless you have auto_comit on of course...)
  • Why shouldn't I use after_transaction in JTA apps?
  • Is my assumption correct that after_transaction should fix the described issue?

Any help is appreciated!

Overage answered 7/4, 2017 at 15:50 Comment(3)
Did you ever get an answer to this? I am also looking at using release_mode after_transaction on wildfly but unsure.Fingerling
Nope, looks like nobody understands this stuff :(Overage
Have a look here: vladmihalcea.com/2015/12/22/…Romanov
A
5

6 years later, but I hope this can help future readers.

Background

For a couple of years, we have encountered a production bug that kept exhausting the pooled connection in an Atomikos managed Hibernate (3.x.x) & JTA integration.

With our Atomikos "recovery strategy" (i.e. force release all connections), this was fine until recent upscale with direct modern collaborators with multiple instances in K8S pushed the app's tipping point where we needed to address this issue.

Navigating around, I found the following set:

setProperty("hibernate.connection.release_mode", "after_transaction");

Which after research it led me to this question (and other multiple unclear/unanswered questions regarding this mode)

So here are the findings:

Origin of Flag

In 2005, it seems that a Hibernate JTA integration was causing issues, as a result HHH-1287 was raised:

It looks like the ExtendedJTATransaction is simply not available after the CMT completes and the WebSphereExtendedJTATransactionLookup class attempts to look it up at java:comp/websphere/ExtendedJTATransaction as part of the normal 'after completion' callback.

The problem occurs when the afterCompletion callback event fires and the ConnectionManager.isAggressiveRelease() method is called from ConnectionManager.afterTransaction(). This attempts to check to see if a transaction is in progress. This test in fact causes the transaction manager to be created (together with a look up of the current transaction) The lookup of the ExtendedJTATransaction fails and the an exception is thrown (see stack trace below).

Although there may be an inconsistency in the way that a SSB and MDB operate, It seems fair to say that the transaction may not be available if it has completed. A workaround is therefore requested.

As a result a change was committed to circumvent the JTA transaction check in this scenario in the connection manager: (This has then gone though further improvements)

private boolean isAggressiveReleaseNoTransactionCheck() {
    if (releaseMode == ConnectionReleaseMode.AFTER_STATEMENT) {
        return true;
    }
    else {
        boolean inAutoCommitState;
        try {
            inAutoCommitState = isAutoCommit();
        }
        catch( SQLException e ) {
            inAutoCommitState=true; // assume we are in an auto-commit state
        }
        return releaseMode == ConnectionReleaseMode.AFTER_TRANSACTION && inAutoCommitState;
    }
}

Feature Release

After verifying this works, it was released in the wild with the following documentation for 3.x.x:

Table 3.4. Hibernate JDBC and Connection Properties

Property name Purpose
hibernate.connection.release_mode Specify when Hibernate should release JDBC connections. By default, a JDBC connection is held until the session is explicitly closed or disconnected. For an application server JTA datasource, you should use after_statement to aggressively release connections after every JDBC call. For a non-JTA connection, it often makes sense to release the connection at the end of each transaction, by using after_transactionauto will choose after_statement for the JTA and CMT transaction strategies and after_transaction for the JDBC transaction strategy. eg. auto (default) / on_close / after_transaction / after_statement

For an application server JTA datasource, you should use after_statement to aggressively release connections after every JDBC call.

Given conclusion

Therefore, this was work around certain containers (not just EE containers) that implement "resource containment" checks.

The Hibernate Session defers getting a JDBC Connection until it actually needs one, which can lead to cases like the following where 2 beans share a Session/EM:

  • Bean1: get Session, but don't use it yet in way that needs Connection
  • Bean1: call Bean2...
  • Bean2: get Session, do some work forcing Session to obtain Connection
  • Bean2: return (Session still hold Connection)

At this point, these containers see this as a "leaked" Connection because the handle was not released by the end of the scope in which it was obtained. Hence, aggressive releasing.

You can read more about this in detail here: [hibernate-dev] - Connection release modes

Useful References and Resources:

Alcinia answered 3/3, 2023 at 14:42 Comment(0)
I
0

Problems with connection pool management can occur at several levels, database, hibernate, application server. In order to facilitate this management, it is strongly recommended to use C3p0 which is a Java library that provides a convenient way for managing database connections. See document C3Po link

You can then configure in your hibernate.cfg.xml file the release mode of JTA transactions. It is best to leave it at the default value: "auto", as shown below:

<property name="hibernate.connection.release_mode">auto</property><!-- Release mode database connection- auto the default value -->
<property name="hibernate.c3p0.max_statements">0</property> <!--  Number of prepared statements will be cached. 0 no caching -->
<property name="hibernate.c3p0.max_size">1000</property> <!-- Max connection pool size -->
<property name="hibernate.c3p0.min_size">50</property> <!-- Min connection pool size -->
<property name="hibernate.c3p0.timeout">550</property> <!-- Time in seconds before free a connection. 0 no expiration --> 
<property name="hibernate.c3p0.idleConnectionTestPeriod">1800</property> <!--  idle time in seconds before testing if a connection is valid - Setting a fairly long idleConnectionTestPeriod, and not testing on checkout and check-in at all is an excellent, high-performance approach. -->
<property name="hibernate.c3p0.preferredTestQuery">SELECT 1;</property>
Instar answered 11/10, 2022 at 10:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.