Two transaction-timeout correctness improvements: a fix so a doomed transaction reusing the same connection is now interrupted on every subsequent use, not just the first, plus a new opt-in option to bound a REQUIRES_NEW transaction's timeout to its suspended parent's remaining time. Also includes an SLF4J 2.x detection fix and a connection-pool idle-eviction regression fix.
You can now resolve the Atomikos subscription (license) content in-memory at startup instead of only from a file on disk -- for example fetched from a secrets vault such as Azure Key Vault, HashiCorp Vault, or AWS Secrets Manager. This means the subscription properties and signature no longer have to be persisted anywhere on the server's file system to satisfy security audits or to keep license material out of lower environments.
SubscriptionContentProvider SPI lets you register a fully-configured provider instance via Configuration.setSubscriptionContentProvider(...); at startup Atomikos calls it to obtain the subscription properties and signature as InputStream objects, and never instantiates or configures the provider itself -- you construct it with your own vault client and credentials, the same pattern as registering a custom XADataSource. If no provider is registered, resolution falls back to the pre-existing lookup order: SubscriptionContentProvider
com.atomikos.icatch.subscription_folder file location
Base64SubscriptionContentProvider is also available for cases where no custom provider class is needed: it reads the subscription properties and signature as base64-encoded content from two new system properties, populated by your own secrets tooling (e.g. a Kubernetes Secret or a Vault agent) before the JVM starts -- this only keeps the license material off the filesystem if that base64 value is itself injected at runtime rather than hardcoded into a script or file that is persisted on disk or in version control.
com.atomikos.icatch.config.SubscriptionContentProvider, registered via the new Configuration.setSubscriptionContentProvider(...) and getSubscriptionContentProvider() methods. New system properties com.atomikos.icatch.subscription_properties_base64 and com.atomikos.icatch.subscription_signature_base64 activate the built-in Base64SubscriptionContentProvider. None of this is active unless you register a provider or set these properties.
You can now see recovery-scan outcomes in the logs at INFO level without enabling full transaction-trace debug logging: replay-commit and presumed-abort decisions are logged at INFO, and a new event reports how many prepared XIDs a resource's recovery scan actually returned. This means diagnosing a slow-to-resolve in-doubt transaction no longer requires turning on debug logging that also captures every normal transaction's participant-commit/abort activity.
ReplayCommitEvent and PresumedAbortEvent, published by XARecoveryManager, are now handled by RecoveryMonitor instead of TransactionTraceMonitor, so they log at INFO independently of transaction-trace debug logging; the duplicate handling previously in TransactionTraceMonitor was removed. A new XidsRecoveredEvent is published after each resource's recovery scan, carrying counts only: the total number of prepared XIDs returned by the resource's xa_recover() call, how many were recognized as this transaction manager's own, and how many belonged to other transaction managers sharing the same resource manager. The raw XID list itself is not exposed by this event -- in a busy shared backend that list can be routinely large, so only the bounded counts are surfaced by default.
ReplayCommitEvent and PresumedAbortEvent logging moved from com.atomikos.monitoring.TransactionTraceMonitor to com.atomikos.monitoring.RecoveryMonitor, and now logs at INFO rather than only when DEBUG is enabled on that logger. If your logging configuration sets levels on either of those two classes specifically to see these events, review it after upgrading. A new event type, com.atomikos.icatch.event.recovery.XidsRecoveredEvent, is published to registered EventListener implementations.
RecoveryFailedEvent, instead of only the affected resource's name. This means a monitoring dashboard subscribed to RecoveryFailedEvent can now tell, for example, a resource-manager-unavailable failure apart from a rollback failure, without cross-referencing raw log files.
XATransactionalResource.recover() now captures the XAException encountered during a resource's recovery scan or a heuristic-outcome rollback and passes its message and XA error code through to RecoveryFailedEvent, instead of only logging and swallowing the exception. The separate, cause-less publish of RecoveryFailedEvent previously done by RecoveryDomainService.performRecovery() was removed, since XATransactionalResource.recover() now publishes the event itself with the failure detail attached.
RecoveryFailedEvent (com.atomikos.icatch.event.recovery.RecoveryFailedEvent) now carries a cause message and an XA error code in addition to the resource name. Existing consumers of the event are unaffected but can now read this extra detail.
You can now cap a REQUIRES_NEW transaction's timeout to the remaining time of the transaction it suspends, so a compound business operation's overall deadline is respected even across an independent REQUIRES_NEW sub-step. This is opt-in and off by default: with nothing configured, a REQUIRES_NEW transaction keeps getting its own full default timeout, exactly as before.
suspend() and resume()). If a new transaction begins while one is suspended -- the REQUIRES_NEW case -- its timeout is capped to that suspended transaction's live remaining time, re-read at the moment the new transaction starts (not a stale snapshot taken when it was suspended). The cap only ever reduces the requested timeout, never extends it: if the suspended transaction has more time left than the new transaction's own default, the default is used unchanged. If more than one transaction is suspended on the same thread (nested REQUIRES_NEW), the most recently suspended one is used. No artificial minimum is applied: if the suspended transaction is nearly out of time, the new transaction gets a correspondingly short timeout rather than a padded one.
com.atomikos.icatch.feature.230271, default false (disabled) -- must be explicitly enabled (in jta.properties or as a system property) to activate this behaviour.
You can now enable a partitioned connection-pool tracking strategy that keeps in-use and available connections in separate collections, reducing contention when borrowing and enlisting connections under concurrent load.
PartitionedConnectionPool implementation (selected through a new ConnectionPoolFactory behind the XConnectionPool interface, alongside the existing ConnectionPool) tracks available and in-use connections in separate collections, so borrow requests only scan available connections and idle-connection maintenance only removes from the available set. This is opt-in via the com.atomikos.icatch.feature.216947 flag, which defaults to false (disabled); with the flag left at its default, connection pooling is unchanged and continues to use the existing ConnectionPool implementation.
com.atomikos.icatch.feature.216947 system property / jta.properties entry to true switches JDBC/JMS connection pooling to the new PartitionedConnectionPool implementation.
com.atomikos.icatch.feature.227307=true) to catch a transaction that times out partway through a sequence of statements on the same, already-enlisted connection, not only on its first statement. This means a long-running transaction that reuses one connection across multiple statements is now correctly interrupted at the first use after it times out, not only when it commits.
The guard introduced in 6.0.117 checked whether a transaction was doomed (timed out or marked rollback-only) only at the point a resource was first enlisted. If the same connection was then reused for several sequential statements within that transaction, later statements were not re-checked, so a transaction that timed out partway through would not be interrupted until it reached commit. The guard now re-checks doomed status on every subsequent use of an already-enlisted connection, not only the first.
com.atomikos.icatch.feature.227307 flag introduced in 6.0.117 (still false by default) -- this is a refinement to that flag's existing behaviour, not a new activation mechanism.
ConfigProperties (e.g. ConfigProperties.FEATURE_227307) instead of a raw string literal.
ConfigProperties gained FEATURE_207056, FEATURE_226870, FEATURE_227307, and FEATURE_230271 constants for use with getFeatureFlag(...). This is a purely additive convenience -- existing code passing the raw string id continues to work unchanged. A flag that graduates (its default becomes permanent) or is retired (its property is removed) keeps its constant, marked @Deprecated with javadoc explaining what happened, rather than having it deleted.
getFeatureFlag("NNNNN") calls with a raw string literal continue to work unchanged. New, optional: ConfigProperties.FEATURE_207056, FEATURE_226870, FEATURE_227307, FEATURE_230271 constants.
| Severity: | 3 |
|---|---|
| Affected version(s): | 6.0.x |
minPoolSize connections on every maintenance cycle when the pool is otherwise idle. This means an idle pool stays at rest instead of continuously destroying and recreating its minimum connections, avoiding unnecessary reconnect churn and blocking I/O held under the pool's internal lock.
ConnectionPool.removeIdleConnectionsIfMinPoolSizeExceeded() had lost its minPoolSize cap in an earlier change, so every maintenance pass destroyed all idle connections past maxIdleTime -- including the core minPoolSize ones -- which were then immediately recreated in the same cycle. The cap is restored: idle connections are now evicted only above minPoolSize, matching the behaviour of the newer PartitionedConnectionPool. Existing connection-validation (connectionValidationInterval) and maxLifetime settings already cover stale-connection detection, so no opt-in flag was needed for this fix.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.x |
Atomikos logging no longer silently falls through to log4j2, log4j, or java.util.logging when SLF4J 2.x is on the classpath. This means SLF4J 2.x users now get their Atomikos log output routed through SLF4J as expected, without any configuration change.
org.slf4j.impl.StaticLoggerBinder, a class SLF4J 2.x removed in favor of a ServiceLoader-based mechanism; on SLF4J 2.x that probe failed silently and Atomikos fell back to whatever other logging framework was present on the classpath. com.atomikos.logging.LoggerFactory now also probes for org.slf4j.spi.SLF4JServiceProvider, so both SLF4J 1.7.x (via StaticLoggerBinder) and 2.x (via SLF4JServiceProvider) are detected; if neither is present, Atomikos falls back to its existing behaviour unchanged.
None.
forceConnectionIntoXaMode workaround on spec-compliant JMS
providers and on Oracle AQ 19c and later.
Atomikos now refuses to enlist a resource on a transaction that has already timed out or been marked rollback-only, interrupting a doomed transaction early rather than letting it proceed and fail later at commit. This behaviour is opt-in and off by default.
com.atomikos.icatch.feature.227307=true to your
jta.properties (off by default in this release for backward compatibility).
With the flag on, the refusal happens before XA START, so no XA branch is
ever started: the doomed transaction rolls back through the normal path and the
borrowed pooled connection or JMS session returns to the pool via the managed
lifecycle (no leak). On the JDBC side the refusal surfaces to your code as an
AtomikosSQLException (a normal SQLException); on the JMS side as a
JMSException. The check is a cheap timeout/state test done before XA START —
for a doomed transaction it actually saves the wasted round-trip to the backend.
Because a flow that previously relied on the late (commit-time) failure will now
fail fast at enlistment, we ship it off by default; enable it in a test
environment first, then roll it out more broadly.
None. The behaviour is opt-in via a feature flag and off by default.
An already-timed-out coordinator no longer resets an enlisted resource's own transaction timeout to the backend default. This means a resource enlisted on an expired transaction is no longer held longer than necessary.
getTimeout() < 0=),
XAResourceTransaction computed the remaining time and passed it to
XAResource.setTransactionTimeout. Per the JTA/XA contract,
setTransactionTimeout(0) means "reset to the default timeout", so the backend
did not learn that the transaction had expired and reset its own timeout to the
default — holding XA resources unnecessarily long. Atomikos now avoids passing a
zero-or-negative value, so it no longer resets the resource timeout when the
coordinator has already timed out. (Surfaced alongside the doomed-enlistment
guard, also in this release.)
None.
forceConnectionIntoXaMode workaround,
avoiding wasteful per-session churn on spec-compliant JMS providers and on
Oracle AQ 19c and later.
createXASession() call, purely to coax older Oracle AQ into XA mode; for
spec-compliant JMS providers (and Oracle AQ 19c+) this is unnecessary churn.
Control it with com.atomikos.icatch.feature.226870 in jta.properties. The
flag has inverted semantics: true keeps the legacy workaround (required for
pre-19c Oracle AQ), false skips it. In this release the default is true
(workaround preserved) for backward compatibility; set it to false if you run
on Oracle AQ 19c+ or a spec-compliant JMS provider.
None. Behaviour is controlled by an opt-in feature flag; the default preserves the previous behaviour.
Concerning security and vulnerabilities: the following are the runtime dependencies (the SBOM) of our product. As you can see, the only transitive third-party dependencies are for the Spring Boot integration modules — because that is the only way to integrate with Spring Boot. All other modules / jars have no third-party runtime dependencies whatsoever.
This is compile + runtime scope;provided, test and non-propagating
optional dependencies are excluded, so it is what your application
actually receives. Look up the module(s) your application depends on.
To reproduce it yourself, run this in a project that depends on the
Atomikos artifacts you use (use exactly this — not a bare dependency:tree,
which would also list optional/provided libraries you are not given):
mvn dependency:list -DincludeScope=runtime
transactions transactions-api transactions-eclipselink transactions-hibernate2 subscription transactions-hibernate3 transactions-hibernate4 transactions-jdbc transactions-jms transactions-jndi-provider transactions-jta transactions-osgi transactions-remoting atomikos-util transactions-allegrograph transactions-hazelcast transactions-jmx transactions-jsp transactions-logcloud transactions-logutil transactions-micrometer transactions-monitoring transactions-monitoring-logs transactions-monitoring-stderr transactions-opentracing transactions-osgi-axt transactions-remoting-recovery transactions-spring transactions-spring-boot-logcloud transactions-tomcat
transactions-spring-boot org.springframework.boot:spring-boot:2.3.4.RELEASE org.springframework:spring-aop:5.2.9.RELEASE org.springframework:spring-beans:5.2.9.RELEASE org.springframework:spring-context:5.2.9.RELEASE org.springframework:spring-core:5.2.9.RELEASE org.springframework:spring-expression:5.2.9.RELEASE org.springframework:spring-jcl:5.2.9.RELEASE org.springframework:spring-tx:5.2.9.RELEASE transactions-spring-boot-starter org.springframework.boot:spring-boot:2.3.4.RELEASE org.springframework:spring-aop:5.2.9.RELEASE org.springframework:spring-beans:5.2.9.RELEASE org.springframework:spring-context:5.2.9.RELEASE org.springframework:spring-core:5.2.9.RELEASE org.springframework:spring-expression:5.2.9.RELEASE org.springframework:spring-jcl:5.2.9.RELEASE org.springframework:spring-tx:5.2.9.RELEASE transactions-spring-boot3 jakarta.jms:jakarta.jms-api:3.1.0 jakarta.transaction:jakarta.transaction-api:2.0.1 org.springframework.boot:spring-boot:3.0.1 org.springframework:spring-aop:6.0.3 org.springframework:spring-beans:6.0.3 org.springframework:spring-context:6.0.3 org.springframework:spring-core:6.0.3 org.springframework:spring-expression:6.0.3 org.springframework:spring-jcl:6.0.3 org.springframework:spring-tx:6.0.3 transactions-spring-boot3-starter jakarta.jms:jakarta.jms-api:3.1.0 jakarta.transaction:jakarta.transaction-api:2.0.1 org.springframework.boot:spring-boot:3.0.1 org.springframework:spring-aop:6.0.3 org.springframework:spring-beans:6.0.3 org.springframework:spring-context:6.0.3 org.springframework:spring-core:6.0.3 org.springframework:spring-expression:6.0.3 org.springframework:spring-jcl:6.0.3 org.springframework:spring-tx:6.0.3 transactions-spring-boot3.4 io.micrometer:micrometer-commons:1.12.0 io.micrometer:micrometer-observation:1.12.0 jakarta.jms:jakarta.jms-api:3.1.0 jakarta.transaction:jakarta.transaction-api:2.0.1 org.springframework.boot:spring-boot:3.2.0 org.springframework:spring-aop:6.1.1 org.springframework:spring-beans:6.1.1 org.springframework:spring-context:6.1.1 org.springframework:spring-core:6.1.1 org.springframework:spring-expression:6.1.1 org.springframework:spring-jcl:6.1.1 org.springframework:spring-tx:6.1.1 transactions-spring-boot3.4-starter io.micrometer:micrometer-commons:1.12.0 io.micrometer:micrometer-observation:1.12.0 jakarta.jms:jakarta.jms-api:3.1.0 jakarta.transaction:jakarta.transaction-api:2.0.1 org.springframework.boot:spring-boot:3.2.0 org.springframework:spring-aop:6.1.1 org.springframework:spring-beans:6.1.1 org.springframework:spring-context:6.1.1 org.springframework:spring-core:6.1.1 org.springframework:spring-expression:6.1.1 org.springframework:spring-jcl:6.1.1 org.springframework:spring-tx:6.1.1 transactions-spring-boot4 ch.qos.logback:logback-classic:1.5.21 ch.qos.logback:logback-core:1.5.21 com.zaxxer:HikariCP:7.0.2 commons-logging:commons-logging:1.3.5 io.micrometer:micrometer-commons:1.16.0 io.micrometer:micrometer-observation:1.16.0 jakarta.annotation:jakarta.annotation-api:3.0.0 jakarta.jms:jakarta.jms-api:3.1.0 jakarta.transaction:jakarta.transaction-api:2.0.1 org.apache.logging.log4j:log4j-api:2.25.2 org.apache.logging.log4j:log4j-to-slf4j:2.25.2 org.jspecify:jspecify:1.0.0 org.slf4j:jul-to-slf4j:2.0.17 org.slf4j:slf4j-api:2.0.17 org.springframework.boot:spring-boot-autoconfigure:4.0.0 org.springframework.boot:spring-boot-data-commons:4.0.0 org.springframework.boot:spring-boot-data-jdbc:4.0.0 org.springframework.boot:spring-boot-jdbc:4.0.0 org.springframework.boot:spring-boot-jms:4.0.0 org.springframework.boot:spring-boot-persistence:4.0.0 org.springframework.boot:spring-boot-sql:4.0.0 org.springframework.boot:spring-boot-starter-data-jdbc:4.0.0 org.springframework.boot:spring-boot-starter-jdbc:4.0.0 org.springframework.boot:spring-boot-starter-jms:4.0.0 org.springframework.boot:spring-boot-starter-logging:4.0.0 org.springframework.boot:spring-boot-starter:4.0.0 org.springframework.boot:spring-boot-transaction:4.0.0 org.springframework.boot:spring-boot:4.0.0 org.springframework.data:spring-data-commons:4.0.0 org.springframework.data:spring-data-jdbc:4.0.0 org.springframework.data:spring-data-relational:4.0.0 org.springframework:spring-aop:7.0.1 org.springframework:spring-beans:7.0.0 org.springframework:spring-context:7.0.1 org.springframework:spring-core:7.0.0 org.springframework:spring-expression:7.0.1 org.springframework:spring-jdbc:7.0.1 org.springframework:spring-jms:7.0.1 org.springframework:spring-messaging:7.0.1 org.springframework:spring-tx:7.0.0 org.yaml:snakeyaml:2.5 transactions-spring-boot4-starter ch.qos.logback:logback-classic:1.5.21 ch.qos.logback:logback-core:1.5.21 com.zaxxer:HikariCP:7.0.2 commons-logging:commons-logging:1.3.5 io.micrometer:micrometer-commons:1.16.0 io.micrometer:micrometer-observation:1.16.0 jakarta.annotation:jakarta.annotation-api:3.0.0 jakarta.jms:jakarta.jms-api:3.1.0 jakarta.transaction:jakarta.transaction-api:2.0.1 org.apache.logging.log4j:log4j-api:2.25.2 org.apache.logging.log4j:log4j-to-slf4j:2.25.2 org.jspecify:jspecify:1.0.0 org.slf4j:jul-to-slf4j:2.0.17 org.slf4j:slf4j-api:2.0.17 org.springframework.boot:spring-boot-autoconfigure:4.0.0 org.springframework.boot:spring-boot-data-commons:4.0.0 org.springframework.boot:spring-boot-data-jdbc:4.0.0 org.springframework.boot:spring-boot-jdbc:4.0.0 org.springframework.boot:spring-boot-jms:4.0.0 org.springframework.boot:spring-boot-persistence:4.0.0 org.springframework.boot:spring-boot-sql:4.0.0 org.springframework.boot:spring-boot-starter-data-jdbc:4.0.0 org.springframework.boot:spring-boot-starter-jdbc:4.0.0 org.springframework.boot:spring-boot-starter-jms:4.0.0 org.springframework.boot:spring-boot-starter-logging:4.0.0 org.springframework.boot:spring-boot-starter:4.0.0 org.springframework.boot:spring-boot-transaction:4.0.0 org.springframework.boot:spring-boot:4.0.0 org.springframework.data:spring-data-commons:4.0.0 org.springframework.data:spring-data-jdbc:4.0.0 org.springframework.data:spring-data-relational:4.0.0 org.springframework:spring-aop:7.0.1 org.springframework:spring-beans:7.0.0 org.springframework:spring-context:7.0.1 org.springframework:spring-core:7.0.0 org.springframework:spring-expression:7.0.1 org.springframework:spring-jdbc:7.0.1 org.springframework:spring-jms:7.0.1 org.springframework:spring-messaging:7.0.1 org.springframework:spring-tx:7.0.0 org.yaml:snakeyaml:2.5
Release notes for ExtremeTransactions 6.1.116
com.atomikos.icatch.feature.207056=true
The new concurrency model is implemented by 2 new core classes:
| Severity: | 4 |
|---|---|
| Affected version(s): | 5.0.x, 6.0.x |
We now check for timeout of a local sub transaction when the parent transaction commits.
Before this fix, a sub transaction could timeout but this would not block prepare of the parent transaction, leading to unnecessary prepare work and log warnings.
We now check for timeout and fail early when prepare is attempted.
None.
| Severity: | 2 |
|---|---|
| Affected version(s): | 6.0.x |
You can now use our JTA/XA connections with your own connection pools.
Our JTA/XA connection proxies would not work with external pools. This should now be possible.
Based on a contribution from Open J Proxy (OJP) - an open source database proxy that supports distributed transactions.Courtesy of the Open J Proxy team - thanks for contributing!
Also see the full details on GitHub.AtomikosNonPoolingDataSourceBean as the datasource.
| Severity: | 3 |
|---|---|
| Affected version(s): | 6.0.x |
We now avoid that a growing pool's connections are "hijacked" by threads whose requests came in later than the waiting thread.
None.
You can now use Atomikos with Spring Boot 4
Add the following dependency to your pom in order to use this starter:
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-spring-boot4-starter</artifactId>
<version>...</version>
</dependency>
You can now use Atomikos with Spring Boot 3.4
Add the following dependency to your pom in order to use this starter:
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-spring-boot3.4-starter</artifactId>
<version>...</version>
</dependency>
You can now use our Hibernate 7 example for inspiration of your project.
You can now check a basic JakartaEE example.
The 6.0 release line added support for JakartaEE, but without examples so far.
We have now added some.
None.
We now retry obtaining a file lock on startup.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.x |
Interposed synchronisation instances are now also called on regular rollback.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.x |
Our AtomikosSQLException is now in the public package of module transactions-jdbc.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.x |
We (and you) now use the jta and jms versions of Spring Boot's POM for the starter project.
The JTA and JMS version dependencies are now aligned with Spring Boot.
We did this already for later Spring Boot integrations, but not yet for Spring Boot 2.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.x |
We now use a more recent h2 version.
The pom of the Hibernate 6 examples project has been updated to use a better suitable h2 version.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.x |
Cleaned up the pom file for transactions-eclipselink.
The pom file used to reference an extra repository - but it turns out this was not needed with some minor tweaks in the pom.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.x |
The OSGi service name now has the correct version.
Features can now be enabled/disabled via feature flag support in the configuration properties:
com.atomikos.icatch.feature.<ID>=...
It can be set to true or false, and helps us with feature flags for risky code changes so we can always fallback to the previous behaviour.
| Severity: | 3 |
|---|---|
| Affected version(s): | 5.0.x, 6.0.x |
You now get a descriptive message that signals rollback-only instead of suggesting a timeout.
The customer report is included with the full details below:
some of our applications occasionally log Exceptions like this during execution:
WARN c.a.j.internal.AtomikosSQLException - The transaction has timed out - try increasing the timeout if needed
WARN c.a.j.i.AtomikosJdbcConnectionProxy - Error enlisting in transaction - connection might be broken? Please check the logs for more information...
com.atomikos.jdbc.internal.AtomikosSQLException: The transaction has timed out - try increasing the timeout if needed
at com.atomikos.jdbc.internal.AtomikosSQLException.throwAtomikosSQLException(AtomikosSQLException.java:29)
at com.atomikos.jdbc.internal.AtomikosSQLException.throwAtomikosSQLException(AtomikosSQLException.java:40)
at com.atomikos.jdbc.internal.AtomikosJdbcConnectionProxy.enlist(AtomikosJdbcConnectionProxy.java:97)
at com.atomikos.jdbc.internal.AtomikosJdbcConnectionProxy.updateTransactionContext(AtomikosJdbcConnectionProxy.java:61)
at com.atomikos.jdbc.internal.AbstractJdbcConnectionProxy.prepareStatement(AbstractJdbcConnectionProxy.java:64)
At first glance, developers thought of an transaction timeout problem, trying to increase the tx-timeout. But in this, timeout increasing did not help. The reason for this exception was previous SQLException which went through a Spring @Transactional method, marking the actual Transaction ‚rollback-only‘.
Clearer reports in the log.
| Severity: | 3 |
|---|---|
| Affected version(s): | 6.0.x |
We now avoid adding the same statement many times to the collection of open statements.
We keep a collection of open JDBC statements so they can be closed when the JDBC connection is closed.
Our AbstractJdbcConnectionProxy class used to add a same statement multiple times to the collection of open statements and could lead to high memory consumption over time. This was fixed.
None.
| Severity: | 3 |
|---|---|
| Affected version(s): | 6.0.x |
We now avoid useless calls to the XAResource on close.
Closing a resource would also remove it from the Configuration like this:
public static RecoverableResource removeResource ( String name )
{
RecoverableResource ret = null;
if ( name != null ) {
ret = (RecoverableResource) resources_.remove ( name );
if ( ret != null ) resourceList_.remove ( ret );
}
return ret;
}
In particular, the additional removal from the resourceList would trigger a call to equals, which in turn expects the XAResource to be available. But this is problematic if the resource was already closed.
Solution: we removed the resourceList since it was not really required.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.x |
You can now see more descriptive state information to assess timeout possibility.
Instead of suggesting a timeout, we now hint at timeout and show the actual transaction state in the exception. This allows developers to assess the right actionable steps to take.
For more info, see GitHubNone.
You can now set the logCloudDsName via Spring Boot.
Quoting the customer's report:
Regarding the (JNDI) name of the LogCloud datasource bean used by Atomikos for datasource lookup, there is actually a property com.atomikos.icatch.logcloud_datasource_name. However, this cannot be set in Spring Boot applications via spring.jta.atomikos.properties..., because this property is missing in SpringJtaAtomikosProperties and AtomikosProperties.
You can now use a Hikari datasource for logging the the LogCloud. Just point to it via the logcloud datasource name property.
You can now see the pool's percentage used (wrt its capacity) in our Micrometer support module.
The ability to see the pool's percentage used (wrt its capacity) was already present in our JMX module, but not in our Micrometer support. This has now been added.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.113 |
You can now use the new Spring Boot 3.4 starter.
None.
| Severity: | 3 |
|---|---|
| Affected version(s): | 6.0.x |
The error message on potential timeouts is now better.
Some cases would report an error like "The transaction has timed out - try increasing the timeout if needed" when in fact the cause was a wrong state of the transaction.
This has been improved to also show state information:
"The transaction has potentially timed out (state: " + state + ") - try increasing the timeout if needed"
None.
| Severity: | 2 |
|---|---|
| Affected version(s): | 6.0.x |
The implementation of this class is now safer for multi-threaded use.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.x |
The port number has been corrected in the README of the tomcat examples.
The README file would contain port 8080 instead of 8888. This has been fixed.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.x |
The new Tomcat examples should now include the right Atomikos release.
Due to an issue with maven plugins, the examples would not always ship the right Atomikos release. This has now been fixed.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.x |
The OSGi examples are now skipped during the build.
The OSGi examples used bundle dependencies hosted on a Spring repository site that has been discontinued. This made the build fail. Until we find a solution, we had to disable this module during the build (or releases would be blocked).
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.x |
The zip files with example projects failed to upload.
When trying to download the example projects from the installation page(s) you will get "404 Not Found" errors. We are looking into it but decided not to let this block a maintenance release like this one.
You can now use Atomikos with Spring Boot 3.4.
Spring Boot 3.4 required a new starter project to make it work with Atomikos.
Attempting to use Spring Boot 3.4 with the older starter project would result in errors like this:
Caused by: java.lang.NoSuchMethodError: 'void org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers.customize(org.springframework.transaction.PlatformTransactionManager)' at com.atomikos.spring.AtomikosAutoConfiguration.lambda$transactionManager$0(AtomikosAutoConfiguration.java:84) at org.springframework.beans.factory.support.DefaultListableBeanFactory$DependencyObjectProvider.ifAvailable(DefaultListableBeanFactory.java:2382) at com.atomikos.spring.AtomikosAutoConfiguration.transactionManager(AtomikosAutoConfiguration.java:84) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:171) ... 50 moreThis was due to Spring's removal of some deprecated methods in org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers. A new starter project was needed to fix this.
You can now just use the new starter for your project.
You now get a meaningful error message when the JDBC driver does not return a valid connection.
When the JDBC driver does not return a valid connection, this would result in a cryptic exception like this:
java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "this.delegate" is null
at com.atomikos.util.DynamicProxySupport.getClassLoadersToTry(DynamicProxySupport.java:195) ~[atomikos-util-6.0.112.jar:na]
at com.atomikos.util.DynamicProxySupport.createDynamicProxy(DynamicProxySupport.java:189) ~[atomikos-util-6.0.112.jar:na]
at com.atomikos.jdbc.internal.AtomikosNonXAPooledConnection.doCreateConnectionProxy(AtomikosNonXAPooledConnection.java:108) ~[transactions-jdbc-6.0.112.jar:na]
at com.atomikos.jdbc.internal.AtomikosNonXAPooledConnection.doCreateConnectionProxy(AtomikosNonXAPooledConnection.java:35) ~[transactions-jdbc-6.0.112.jar:na]
at com.atomikos.datasource.pool.AbstractXPooledConnection.createConnectionProxy(AbstractXPooledConnection.java:101) ~[transactions-jta-6.0.112.jar:na]
at com.atomikos.datasource.pool.ConnectionPoolWithConcurrentValidation.concurrentlyTryToUse(ConnectionPoolWithConcurrentValidation.java:61) ~[transactions-jta-6.0.112.jar:na]
at com.atomikos.datasource.pool.ConnectionPoolWithConcurrentValidation.retrieveFirstAvailableConnection(ConnectionPoolWithConcurrentValidation.java:43) ~[transactions-jta-6.0.112.jar:na]
at com.atomikos.datasource.pool.ConnectionPool.retrieveFirstAvailableConnectionAndGrowPoolIfNecessary(ConnectionPool.java:140) ~[transactions-jta-6.0.112.jar:na]
at com.atomikos.datasource.pool.ConnectionPool.findOrWaitForAnAvailableConnection(ConnectionPool.java:128) ~[transactions-jta-6.0.112.jar:na]
at com.atomikos.datasource.pool.ConnectionPool.borrowConnection(ConnectionPool.java:119) ~[transactions-jta-6.0.112.jar:na]
at com.atomikos.jdbc.internal.AbstractDataSourceBean.getConnection(AbstractDataSourceBean.java:375) ~[transactions-jdbc-6.0.112.jar:na]
at com.atomikos.jdbc.AtomikosNonXADataSourceBean.getConnection(AtomikosNonXADataSourceBean.java:208) ~[transactions-jdbc-6.0.112.jar:na]
This has now been fixed: we now report that the "Driver didn't return a valid Connection".
None.
We now avoid useless XA connection refreshing on shutdown.
The following would happen upon shutdown, when for instance the JMS server was gone:
Failed to refresh XAResource
com.atomikos.datasource.ResourceException: Error in getting XA resource
at com.atomikos.datasource.xa.jms.JmsTransactionalResource.refreshXAConnection(JmsTransactionalResource.java:83) ~[!/:?]
at com.atomikos.datasource.xa.XATransactionalResource.refreshXAResource(XATransactionalResource.java:413) ~[!/:?]
at com.atomikos.datasource.xa.XATransactionalResource.getXAResource(XATransactionalResource.java:227) ~[!/:?]
at com.atomikos.datasource.xa.XATransactionalResource.isSameRM(XATransactionalResource.java:317) ~[!/:?]
at com.atomikos.datasource.xa.XATransactionalResource.equals(XATransactionalResource.java:430) ~[!/:?]
at java.util.Vector.indexOf(Vector.java:413) ~[?:1.8.0_381]
at java.util.Vector.indexOf(Vector.java:387) ~[?:1.8.0_381]
at java.util.Vector.removeElement(Vector.java:646) ~[?:1.8.0_381]
at java.util.Vector.remove(Vector.java:804) ~[?:1.8.0_381]
at com.atomikos.icatch.config.Configuration.removeResource(Configuration.java:263) ~[!/:?]
at com.atomikos.jms.AtomikosConnectionFactoryBean.close(AtomikosConnectionFactoryBean.java:597) ~[!/:?]
This has been improved / fixed - we now avoid such refresh.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.112 |
Your getConnection requests now get the (new) connections they deserve.
In our 6.0 release the connection pool grows via a separate background thread. When getConnection finds no available connection, it will start waiting for this thread to grow the pool and add a new connection to it.
The implementation was "unfair" in that a waiting getConnection request could (and would) see its new connection "hijacked" by a different, later getConnection request.
This has now been fixed.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.x, 5.0.x |
You can now safely repeat JNDI lookups for our JDBC and JMS factories bound in Tomcat's JNDI space.
There was a race condition in our code that could lead to repeated initialisation of JNDI resources with the same name, like JDBC datasources or JMS connection factories.
This has now been fixed.
None.
Releases 6.0.110 and 6.0.111 offered a fairer way of growing the connection pool. This has been optimised further.
The two prior releases attempted to offer a fairer way of growing the connection pool, so a thread that requests an extra connection could also use it. However, there the algorithm was still not as good as it could be, because it did the following:
While this performed better than before, this still allowed for another thread to hijack the connection between steps 3 and 4.
We now changed this to the following:
The extra step 3 implies that no other thread can take the connection after step 4. Thus, Thread A is always able to use the new connection.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.110 |
The Tomcat examples have been modified to user Docker, but this does not work on all platforms yet.
The Docker image generated to run the Tomcat examples contains a Java JDK that is not binary compatible with all platforms yet.
| Severity: | 2 |
|---|---|
| Affected version(s): | 6.0.110 |
The improvement shipped as part of release 6.0.110 contained a bug that cause race conditions on concurrent pool usage. This is no longer the case;
The improvement that made growing the pool fairer for concurrent waiting threads contained a bug that led to attempts to use the same connection in two different threads, leading to exceptions like this one:
com.atomikos.datasource.ResourceException: XA resource '5684df3b-2192-4bd1-ba12-91cb2d55edac': resume for XID 'xid://61653731323262342D336561322D343761362D613461632D373861393064643062616539:31302E3130312E31332E392E746D31343035303633' raised -6: the XA resource did not expect this command in the current context at com.atomikos.datasource.xa.XAResourceTransaction.resume(XAResourceTransaction.java:240) at com.atomikos.datasource.xa.session.BranchEnlistedStateHandler.<init>(BranchEnlistedStateHandler.java:42) at com.atomikos.datasource.xa.session.NotInBranchStateHandler.checkEnlistBeforeUse(NotInBranchStateHandler.java:46) at com.atomikos.datasource.xa.session.TransactionContext.checkEnlistBeforeUse(TransactionContext.java:58) at com.atomikos.datasource.xa.session.SessionHandleState.notifyBeforeUse(SessionHandleState.java:185) at com.atomikos.jdbc.internal.AtomikosJdbcConnectionProxy.enlist(AtomikosJdbcConnectionProxy.java:89) at com.atomikos.jdbc.internal.AtomikosJdbcConnectionProxy.updateTransactionContext(AtomikosJdbcConnectionProxy.java:62) at com.atomikos.jdbc.internal.AbstractJdbcConnectionProxy.prepareStatement(AbstractJdbcConnectionProxy.java:65) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at com.atomikos.util.DynamicProxySupport.callProxiedMethod(DynamicProxySupport.java:167) at com.atomikos.util.DynamicProxySupport.invoke(DynamicProxySupport.java:121) at jdk.proxy3/jdk.proxy3.$Proxy235.prepareStatement(Unknown Source) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy$TransactionAwareInvocationHandler.invoke(TransactionAwareDataSourceProxy.java:262) at jdk.proxy3/jdk.proxy3.$Proxy232.prepareStatement(Unknown Source) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:153) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:183) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:155) at org.hibernate.sql.exec.spi.JdbcSelectExecutor.lambda$list$0(JdbcSelectExecutor.java:85) at org.hibernate.sql.results.jdbc.internal.DeferredResultSetAccess.executeQuery(DeferredResultSetAccess.java:231) at org.hibernate.sql.results.jdbc.internal.DeferredResultSetAccess.getResultSet(DeferredResultSetAccess.java:167) at org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl.advanceNext(JdbcValuesResultSetImpl.java:218) at org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl.processNext(JdbcValuesResultSetImpl.java:98) at org.hibernate.sql.results.jdbc.internal.AbstractJdbcValues.next(AbstractJdbcValues.java:19) at org.hibernate.sql.results.internal.RowProcessingStateStandardImpl.next(RowProcessingStateStandardImpl.java:66) at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:202) at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:33) at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:209) at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:83) at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:76) at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:65) at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$2(ConcreteSqmSelectQueryPlan.java:137) at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:381) at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:303) at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:509) at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:427) at org.hibernate.query.Query.getResultList(Query.java:120) at org.springframework.data.jpa.repository.query.JpaQueryExecution$ExistsExecution.doExecute(JpaQueryExecution.java:315) at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:92) at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:149) at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:137) at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:170) at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:158) at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:169) at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:148) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:70) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:379) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:138) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at datadog.trace.instrumentation.springdata.RepositoryInterceptor.invoke(RepositoryInterceptor.java:43) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223) at jdk.proxy3/jdk.proxy3.$Proxy395.existsByRetailTaxpayerIdIn(Unknown Source) at .portfolio_management.taxpayer.PendingSyncService.hasTaxpayerPendingSync(PendingSyncService.java:89) at .portfolio_management.executionaware.evaluation.EvaluationJob$Runner.washGroupCanBeEvaluated(EvaluationJob.java:145) at xxx.portfolio_management.executionaware.evaluation.EvaluationJob$Runner.shouldRunJob(EvaluationJob.java:137) at xxx.portfolio_management.executionaware.evaluation.EvaluationJob$Runner.run_aroundBody0(EvaluationJob.java:113) at xxx.portfolio_management.executionaware.evaluation.EvaluationJob$Runner$AjcClosure1.run(EvaluationJob.java:1) at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96cproceed(AbstractTransactionAspect.aj:67) at org.springframework.transaction.aspectj.AbstractTransactionAspect$AbstractTransactionAspect$1.proceedWithInvocation(AbstractTransactionAspect.aj:73) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:379) at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(AbstractTransactionAspect.aj:71) at xxx.portfolio_management.executionaware.evaluation.EvaluationJob$Runner.run(EvaluationJob.java:112) at xxx.portfolio_management.executionaware.evaluation.EvaluationJob$Runner.run(EvaluationJob.java:61) at xxx.dj.DelayedJobWorker.lambda$process$0(DelayedJobWorker.java:90) at xxx.telemetry.metrics.Metric.lambda$delayedJobTimer$0(Metric.java:25) at io.micrometer.core.instrument.AbstractTimer.record(AbstractTimer.java:187) at xxx.telemetry.metrics.Metric.lambda$delayedJobTimer$1(Metric.java:33) at io.micrometer.core.instrument.AbstractTimer.record(AbstractTimer.java:187) at xxx.telemetry.metrics.Metric.delayedJobTimer(Metric.java:33) at xxx.telemetry.metrics.Metric.delayedJobTimer(Metric.java:29) at xxx.dj.DelayedJobWorker.lambda$process$5(DelayedJobWorker.java:86) at xxx.telemetry.metrics.Metric.lambda$delayedJobTimer$0(Metric.java:25) at io.micrometer.core.instrument.AbstractTimer.record(AbstractTimer.java:187) at xxx.telemetry.metrics.Metric.lambda$delayedJobTimer$1(Metric.java:33) at io.micrometer.core.instrument.AbstractTimer.record(AbstractTimer.java:187) at xxx.telemetry.metrics.Metric.delayedJobTimer(Metric.java:33) at xxx.telemetry.metrics.Metric.delayedJobTimer(Metric.java:29) at xxx.dj.DelayedJobWorker.process(DelayedJobWorker.java:51) at xxx.dj.DelayedJobProcessor.lambda$claimAndSubmitJobs$0(DelayedJobProcessor.java:148) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) at java.base/java.lang.Thread.run(Thread.java:1583) Caused by: org.postgresql.xa.PGXAException: Connection is busy with another transaction at org.postgresql.xa.PGXAConnection.start(PGXAConnection.java:199) at com.atomikos.datasource.xa.XAResourceTransaction.resume(XAResourceTransaction.java:234) ... 94 more
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.110 |
The Tomcat examples have been modified to user Docker, but this does not work on all platforms yet.
The Docker image generated to run the Tomcat examples contains a Java JDK that is not binary compatible with all platforms yet.
You can now benefit from reduced synchronisation overhead thanks to concurrent maps usage in our core classes.
om.atomikos.icatch.feature.207056 = true
This is enabled by default because we are confident it works better than before. If you experience problems after upgrading, set this to false...
You can now shift Kubernetes pods by starting a new pod while the old one is still terminating.
In Kubernetes environments pods might be terminated and shifted to other nodes. Because of this the configured log path might be in use if the old pod is about to terminate and the new one is starting up. To be able to use the same LogFileLock we now offer retry attempts for the new pod which is trying to acquire the lock.
You can now use the same JTA and JMS dependency versions of Spring Boot's rather than the ones we specify.
For Spring Boot 2 we used to specify a particular version for each of JTA and JMS. This would override the versions that Spring Boot prefers. We no longer do this.
None.
You can now check the examples for Hibernate 7.
We've added working samples for Hibernate 7.
| Severity: | 3 |
|---|---|
| Affected version(s): | 6.O.x, 5.0.x |
You can now expect more accurate exception messages when creating a JDBC statement fails
We used to have one generic exception message when a statement could not be created, each time suggesting a timeout of the transaction. This was confusing if the real reason was, for instance, the transaction having been marked for rollback only.
The code has been refined live this:
TxState state = ct.getState();
if (state == TxState.ACTIVE) {
ct.registerSynchronization(new JdbcRequeueSynchronization(this, ct));
} else if (state == TxState.MARKED_ABORT){
AtomikosSQLException.throwAtomikosSQLException("The transaction has been set to rollback-only");
} else {
AtomikosSQLException.throwAtomikosSQLException("The transaction has timed out - try increasing the timeout if needed");
}
None.
| Severity: | 3 |
|---|---|
| Affected version(s): | 6.O.x |
Interposed synchronisation instances are now called on regular rollback also.
None.
| Severity: | 3 |
|---|---|
| Affected version(s): | 6.0.x |
Getting a new connection is now more efficient.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 5.O.x, 6.0.x |
The class AtomikosSQLException was not exposed as public in OSGi.
The class AtomikosSQLException was not exposed as public in OSGi because it was in an "internal" package. This class has been moved to a public package instead, so it can be used with OSGi.
You have to change the imports when your code references this exception.
| Severity: | 3 |
|---|---|
| Affected version(s): | 5.0.x, 6.0.x and prior (decorated) releases |
Timeout / rollback of a subtransaction no longer appears as a commit to the parent transaction.
Timeout with subsequent rollback of a subtransaction would interfere with a later commit of the parent transaction: the state handler for the subtransaction would erroneously reply with READONLY upon 2PC prepare. This would make it seem to the parent transaction as though commit may proceed. We've fixed this by checking for timeout upon prepare of a subtransaction. Most people are not using subtransaction functionality, but those who do will benefit from this fix.
None.
| Severity: | 3 |
|---|---|
| Affected version(s): | 5.0.x, 6.0.x and prior (decorated) releases |
We improved the way imported transactions are handled in the case of network timeouts - so it aligns with our concurrency model.
None.
| Severity: | 3 |
|---|---|
| Affected version(s): | 6.0.x |
Creating many JDBC statements no longer leads to high memory consumption.
For technical reasons we keep a "cached" collection of JDBC statements. Due to a bug, such statements were added multiple times to a list. We fixed this by:
None.
| Severity: | 3 |
|---|---|
| Affected version(s): | 5.0.x, 6.0.x |
We changed the use of a HashMap to a ConcurrentHashMap for pending request synchronisation instances.
None.
| Severity: | 3 |
|---|---|
| Affected version(s): | 4.0.x, 5.0.x, 6.0.x |
Interruptions during Spring Boot shutdown are now handled better by the connection pool.
Full details as disclosed in the original report:
We experienced a somewhat strange behaviour with Atomikos in a situation, where our application (Spring Boot) is shutting down while some threads are waiting for a connection. In this shutdown-situation, Spring Boot sends an 'interupt' to all running threads. The Atomikos ConnectionPool method 'waitForAtLeastOneAvailableConnection()' handles this InterruptedException by invoking the InteruptedExceptionHelper. This in turn logs the exception and re-interrupts the thread. This is the correct pattern to interrupt possible further waits in the call stack.
But the method does not leave the while-loop. This causes a loop for the remaining borrowConnectionTimeout, leading to a very large amount of exception logs.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.x |
You can now use the Tomcat Jakarta functionality in the free trial download.
The relevant jar file for this was missing from the evaluation zip file. It has now been added.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.110 |
The Tomcat examples have been modified to user Docker, but this does not work on all platforms yet.
The Docker image generated to run the Tomcat examples contains a Java JDK that is not binary compatible with all platforms yet.
This release was very hard to do. Not because we wanted many new features included (there are not that many, actually), but rather because it was a balancing act between stability / backwards compatibility and new "breaking change" emerging platforms (specifically: Spring Boot 3, Hibernate 6 and their dependencies on JakartaEE and very recent Java versions).
We think we did a good job: just like the previous release 5.0, this new release can run on "good old" Java 8 for most modules, except for Spring Boot 3 integration (which requires Java 17 as per Spring Boot) and Hibernate 6. So if your application worked with release 5.0 then it should still work, provided that you do the following:
In order to do this, we had to break the transitive dependency mechanism (which, incidentally, also avoids pulling in vulnerable 3rd party code libs). So: except for Spring Boot 3 apps, this means that you will now have to add the following dependency to your pom file (or you risk facing ClassNotFoundExceptions):
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jta</artifactId>
<version>6.0.109</version> <!-- Commercial, for open source use version 6.0.0 -->
</dependency>
<dependency>
<groupId>jakarta.jms</groupId>
<artifactId>jakarta.jms-api</artifactId>
<!-- NOTE: despite "jakarta" in the name, this version is still a javax jar -->
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jta</artifactId>
<version>6.0.109</version> <!-- Commercial, for open source use version 6.0.0 -->
<classifier>jakarta</classifier>
</dependency>
<dependency>
<groupId>jakarta.jms</groupId>
<artifactId>jakarta.jms-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>jakarta.transaction</groupId>
<artifactId>jakarta.transaction-api</artifactId>
<version>2.0.1</version>
</dependency>
AtomikosConnectionFactoryBean:
AtomikosConnectionFactoryBean cf = new AtomikosConnectionFactoryBean();
// 1 sets behaviour like in releases 3.9-5.0, 0 sets behaviour like in releases pre-3.9
cf.setSessionCreationMode(1);
For more details, see the javadoc of the AtomikosConnectionFactoryBean class.
We've removed reap functionality from the pool, so remove any reapTimeout property in your datasource or connection factory config.
Concerning security and vulnerabilities: the following are the runtime dependencies of our product. As you can see, the only transitive 3rd party dependencies are for Spring Boot integration - because that's the only way to integrate with Spring Boot. All other modules / jars have no 3rd party jar dependencies whatsoever.
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ ExtremeTransactionsForMaven --- [INFO] com.atomikos:ExtremeTransactionsForMaven:pom:6.0.109 [INFO] +- com.atomikos:subscription:jar:6.0.109:compile [INFO] | \- com.atomikos:atomikos-util:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-essentials:pom:6.0.109:compile [INFO] +- com.atomikos:transactions-essentials-jakarta:pom:6.0.109:compile [INFO] +- com.atomikos:extreme-transactions:pom:6.0.109:compile [INFO] +- com.atomikos:extreme-transactions-jakarta:pom:6.0.109:compile [INFO] +- com.atomikos:transactions-monitoring-stderr:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-monitoring-logs:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-logcloud:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-allegrograph:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-remoting:jar:6.0.109:compile [INFO] | \- com.atomikos:transactions:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-remoting:jar:jakarta:6.0.109:compile [INFO] +- com.atomikos:transactions-osgi:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-osgi:jar:jakarta:6.0.109:compile [INFO] +- com.atomikos:transactions-logutil:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-osgi-axt:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-osgi-axt:jar:jakarta:6.0.109:compile [INFO] +- com.atomikos:transactions-jsp:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-jsp:jar:jakarta:6.0.109:compile [INFO] +- com.atomikos:transactions-jdbc:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-jdbc:jar:jakarta:6.0.109:compile [INFO] +- com.atomikos:transactions-jms:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-jms:jar:jakarta:6.0.109:compile [INFO] +- com.atomikos:transactions-jta:jar:6.0.109:compile [INFO] | \- com.atomikos:transactions-api:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-jta:jar:jakarta:6.0.109:compile [INFO] +- com.atomikos:transactions-jmx:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-hibernate2:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-hibernate3:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-hibernate4:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-hibernate4:jar:jakarta:6.0.109:compile [INFO] +- com.atomikos:transactions-eclipselink:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-tomcat:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-spring:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-spring:jar:jakarta:6.0.109:compile [INFO] +- com.atomikos:transactions-spring-boot:jar:6.0.109:compile [INFO] | +- org.springframework:spring-tx:jar:5.2.9.RELEASE:compile [INFO] | | +- org.springframework:spring-beans:jar:5.2.9.RELEASE:compile [INFO] | | \- org.springframework:spring-core:jar:5.2.9.RELEASE:compile [INFO] | | \- org.springframework:spring-jcl:jar:5.2.9.RELEASE:compile [INFO] | \- org.springframework.boot:spring-boot:jar:2.3.4.RELEASE:compile [INFO] | \- org.springframework:spring-context:jar:5.2.9.RELEASE:compile [INFO] | +- org.springframework:spring-aop:jar:5.2.9.RELEASE:compile [INFO] | \- org.springframework:spring-expression:jar:5.2.9.RELEASE:compile [INFO] +- com.atomikos:transactions-spring-boot-starter:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-spring-boot3:jar:6.0.109:compile [INFO] | +- jakarta.jms:jakarta.jms-api:jar:3.1.0:compile [INFO] | \- jakarta.transaction:jakarta.transaction-api:jar:2.0.1:compile [INFO] +- com.atomikos:transactions-spring-boot3-starter:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-hazelcast:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-jndi-provider:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-jndi-provider:jar:jakarta:6.0.109:compile [INFO] +- com.atomikos:transactions-monitoring:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-remoting-recovery:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-remoting-recovery:jar:jakarta:6.0.109:compile [INFO] +- com.atomikos:transactions-spring-boot-logcloud:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-opentracing:jar:6.0.109:compile [INFO] +- com.atomikos:transactions-opentracing:jar:jakarta:6.0.109:compile [INFO] +- com.atomikos:transactions-micrometer:jar:6.0.109:compile [INFO] \- com.atomikos:transactions-micrometer:jar:jakarta:6.0.109:compile
If you like the nitty gritty details, then the following sections are for you!
We added a starter for Spring Boot 3.
Spring Boot 3 has made a "big bang" upgrade to Jakarta EE and Java 17, with all complications involved. You can now use Atomikos with Spring Boot 3 by means of our new Spring Boot 3 starter module.
Spring Boot 3 requires Java 17 or higher, plus all JakartaEE libraries (and for course Atomikos releases 6.0 or higher). Note that this means you will also need JakartaEE JMS drivers, and JakartaEE persistence providers. Hurray.
You need the following dependency to use Spring Boot 3:
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-spring-boot3-starter</artifactId>
<version>6.0.109</version>
</dependency>
For the JakartaEE JMS and JTA APIs: we've added those to the Spring Boot 3 starter module already - so you don't have to bother.
The choice for this strategy was heavily driven by our desire to still support Java 8 applications that can't upgrade to Java 17 or JakartaEE right now.
The previous statement probably deserves some explanation: after some initial attempts it was painfully clear to us that upgrading from Java 8 to Java 17 is nothing short of a nightmare.
[Oh and by the way, we figure that this is the reason why extended support for Java 8 is available until 2030, the longest of all Java versions at the time of publication. Yes, that means Java 8 should be supported for longer than Java 17 - go figure that!] Our chosen approach should allow existing installations to upgrade to our 6.0 release without the need to upgrade to JakartaEE and/or Java 17 at the same time.Past experience with our customers has shown that even a "simple" upgrade from Java 6 to Java 8 can be a huge roadblock - especially if the development team is gone and only operations teams are left. So we prefer to keep upgrading a seamless and straightforward process, without requiring needless Java updates at the same time. We are sure that you will appreciate that.
The "downside" of this choice is that you can no longer count on transitive dependencies as much as you did, because many modules now have 2 variants available (and hence the transitive dependencies would not necessarily match the right variant). While this may seem a disadvantage, it actually increases security because there are no longer transitive dependencies on 3rd party jars either (so you avoid pulling in vulnerabilities).
So: you have to add some dependencies manually that were transitive before. But the effort required is significantly lower than the effort it would take to upgrade your code base towards Java 17 and JakartaEE all at once.
As explained in the upgrade section above: you need to declare some extra dependencies. Also, you have to be careful to use the right combination of Jakarta-enabled jars in your application. To this end, we have defined BOM files that list all the jars designed to work together:
You can check these BOMs for inspiration on which jars to use / combine in your application. If you are curious where to find them: check groupId=com.atomikos and artifactId=name_of_BOM_file.
You can now easily use Hibernate 6 in combination with our product!
Hibernate 6 is also in the JakartaEE camp, so of course you need JakartaEE support to be able to use it. Well, as we've explained above: we have done just that.
To use Hibernate 6, it suffices to use transactions-hibernate4 in the jakarta flavour. For a working sample: check the supplied examples project called examples-hibernate6 or see the summary POM snippet below.No real changes are needed, but you do have to add the correct POM dependencies:
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-hibernate4</artifactId>
<version>6.0.109</version>
<classifier>jakarta</classifier>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jdbc</artifactId>
<version>6.0.109</version>
<classifier>jakarta</classifier>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jta</artifactId>
<version>6.0.109</version>
<classifier>jakarta</classifier>
</dependency>
<dependency>
<groupId>jakarta.transaction</groupId>
<artifactId>jakarta.transaction-api</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.1.0</version>
</dependency>
Of course, you also need the Hibernate 6 dependencies themselves - but we'll leave that up to you...
We now have (minimal) support for JMS 2.0.
JMSContext API. Spring Boot 3 does not seem to need it, so that should be fine for now. Attempting to call any of the createContext methods on the AtomikosConnectionFactoryBean will throw UnsupportedOperationException.
Session creation behaviour has changed due to the clarification of session creation behaviour in JMS 2.0 (which is incompatible with what we had in prior releases). As you can see in the table below, the differences are in the combined interpretation of:
localTransactionMode and
Prior to JMS 2.0, session creation had some fuzzy border cases where the interpretation was left to the party implementing the specs (like Atomikos). In JMS 2.0 this has been addressed. Needless to say, the probably of a perfect match with our interpretation was next to zero - so we had to make some changes.
To preserve compatibility your instances ofAtomikosConnectionFactoryBean now offer an extra method setSessionCreationMode(int mode) which changes behaviour as described below. The default is value 2 (JMS 2.0) so for compatibility with 5.0, try value 1. For compatibility with pre-3.9 installations, try value 0.
| existing JTA transaction for thread | localTransactionMode | resulting session |
|---|---|---|
| true | ignored | XA session |
| false | false | XA session |
| false | true | non-XA session according to sessionTransacted/acknowledgeMode parameters |
| localTransactionMode | sessionTransactedFlag | resulting session |
|---|---|---|
| false | ignored | XA session |
| true | ignored | non-XA session according to sessionTransacted/acknowledgeMode parameters |
| localTransactionMode | sessionTransactedFlag | resulting session |
|---|---|---|
| false | true | XA session |
| other | other | non-XA session according to sessionTransacted/acknowledgeMode parameters |
AtomikosConnectionFactoryBean.
TransactionSynchronizationRegistry defined in the more recent JTA specifications.
com.atomikos.icatch.jta.TransactionSynchronizationRegistryImp contained in module transactions-jta.jar.
Unless you are a vendor of persistence providers, you probably won't ever need this class so we'll keep the explanation to a minimum - since vendors of persistence providers already know all there is to know.
An extra class available in our distribution, for you to use if you want to.
com.atomikos.icatch.jta.template.TransactionTemplate are now tread-safe.
The first implementations of our template were not intended for threaded use cases. Based on customer feedback, we have changed that - so you can now reuse the same instance in different threads - just like Spring's template.
Instead of having to create multiple template instances, you can now reuse the same instance in different places of your code base. This should simplify your configuration and code base.
We've improved the pool logic so that borrow requests can better respect the timeout.
borrowConnectionTimeout setting would (and should) allow. That's because there is no easy way to interrupt a blocked IO request.
We now improved this as follows:
borrowConnectionTimeout.
No real changes are needed, except that it should work better.
We have simplified and improved the shutdown logic.
com.atomikos.icatch.default_max_wait_time_on_shutdown. Recovery itself is already bound by a different parameter: com.atomikos.icatch.default_max_timeout. The previous logic used to mix those two and the results were not always clear.
We have simplified this to the following:
com.atomikos.icatch.default_max_wait_time_on_shutdown in your jta.properties file. Beware that shutdown duration is bound by the value of com.atomikos.icatch.default_max_timeout - unless you use the "forceShutdown" option.
com.atomikos.jms.extra.MessageDrivenContainer because they were never used anyway.
com.atomikos.jms.AtomikosConnectionFactoryBean to create connections. The latter is also configured with a user and password, and those are the values that are actually being used.
As a result, keeping two unused properties in the com.atomikos.jms.extra.MessageDrivenContainer class was confusing - so we have removed those.
You need to remove any references to these properties from your configuration.
We've removed the reaping functionality from the pools.
Reaping was when our pools would take away connections that were being held onto for too long.
Historically, reaping functionality has caused more problems / confusion than it solved. Moreover, it was intended to fix application-level connection leaks, meaning bugs in the application (as opposed to bugs in our code base). We felt that became a source of needless complexity.
We believe that the correct way of fixing application-level connection leaks is by fixing the application, rather than abruptly reaping connections away from that application. So our 6.0 release seemed a good time to remove that feature.
reapTimeout from your configuration.
We've updated the dubbo version used in our product to avoid all known vulnerable versions.
None, other than that your application probably needs to upgrade to a higher dubbo version too.
We now help you find out about known vulnerable maven dependencies that your application is using.
With current hacker efforts moving more and more into the application stack via vulnerable open source dependencies, we notice customers are getting worried (or facing audits of their applications). Log4j, anyone?
Our approach has been two-fold:
Starting in the near future, expect more and more "security updates" in that respect.
None.
The pools's maintenance thread will now check all connections - so pool stability improves.
None.
We now require customers to install subscription files for production use.
We've had some bad experiences with subscriptions purchased via resellers / intermediaries, that were first used by a development team, then moved onto other teams in production without us being able to keep track. This has lead to unpleasant experiences for both our customers and ourselves.
For more details, see this documentation page.
| Severity: | 4 |
|---|---|
| Affected version(s): | 5.0.x |
You can now count on the property values from jta.properties to be taken into account even with Spring Boot.
The Atomikos JTA properties implementation in our Spring Boot starter would define default values for many properties, meaning that their value specified jta.properties would not be taken into account. This has now been fixed.
Your properties specified in jta.properties should now work.
| Severity: | 1/2/3/4 |
|---|---|
| Affected version(s): | 5.0.x |
AtomikosRestPort URL is not set (for transactions across remoting calls).
AtomikosRestPort URL was not set, the client template would report a misleading message saying that there is no transaction for the thread. Instead, the root cause is a URL that is missing - so we fixed that for you.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 5.0.x |
You can now use transitive readOnly remoting transactions in all cases.
This is known as a "diamond case" because the invocation diagram looks like a diamond.
This issue has been fixed in the following way: our product will now avoid the readOnly optimisation in this specific scenario. This is still correct, at a minor performance overhead in the exotic cases where this does happen.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 5.0.x |
Now you can close a JDBC connection and also have the Callable- and PreparedStatements closed automatically.
When a JDBC connection is closed by the application (returned to the pool) then the JDBC specification requires all pending statements to be closed as well.
We supported this, but apparently this was not done for all statement types. We fixed this now.
This issue is marked as severity 4 (development use) because we had no real bug reports from any customers. It was something we noticed during a code review.
None.
| Severity: | 2 |
|---|---|
| Affected version(s): | 5.0.x |
You can now use @RequiresNew with imported transactions.
Our code had a side effect of suspend/resume that changed the local sibling count.
Sibling counts help detect orphaned invocations (and their transactional updates to persistent storage) that arise out of lost replies. For instance, consider this scenario with services A and B:
This risk here is the different views of A and B regarding the scope of the transaction: A thinks it commits one update to B, whereas B commits two different updates. This can be a problem for data consistency, so we avoid this by keeping sibling counts at B and A. A constructs its sibling count picture with each result it actually receives with its replies from A. Before commit, A passes on the "count" it has for invocations at B, and if B finds that there is no match then it refuses to commit.
This would avoid the problem outlined above, because in step 4 service A will miss a count, so in step 6 service A will pass a count of 1 for service B, whereas B will see 2 and refuses the commit process.
In short, sibling counts have their purpose. However due to a bug, this was affected by a suspend/resume at service B (when it has @RequiresNew logic inside).
You should now be able to configure @RequiresNew on any service that needs it.
| Severity: | 4 |
|---|---|
| Affected version(s): | 5.0.x |
Any spring.jta properties in Spring Boot should now be taken into account.
This has proven to confuse users, so we now take such spring.jta properties into account.
Any spring.jta properties in Spring Boot should now be taken into account.
| Severity: | 3 |
|---|---|
| Affected version(s): | 3.9.x, 4.0.x, 5.0.x |
We've refined how we deal with lost XA connections during the commit phase.
Some connection issues would lead to needless heuristic exceptions during commit, in particular when the commit was 1-phase (where failure to reach the backend results in resource-internal rollback anyway).We have now refined this so there are no needless heuristic exceptions any more in these cases. At the same time, we have also tried to minimise the number of cases where such connection issues remain.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 5.0.x |
You can now use our pools with TRACE logging and get less exceptions.
None.
| Severity: | 4 |
|---|---|
| Affected version(s): | 6.0.x |
Unlike Spring Boot 3 support, we did not yet add the JMS and JTA dependencies in the Spring Boot 2 starter.
We still have to add the JMS and JTA dependencies in the Spring Boot 2 starter. This is needed because of the removal of transitive dependencies. Until then, you will have to add them yourself.