The Atomikos Blog
You are here: Blog

ExtremeTransactions 6.0
Support for both javax and jakarta EE

06 May 2023 | Guy Pardon | Release notes

Added sup­port for Jakar­ta EE, Spring Boot 3 and Hiber­nate 6.

TransactionsEssentials 6.0
Release notes for the 6.0 release

13 January 2023 | Guy Pardon | Release notes

Up­grad­ing from 5.0 to 6.0

This re­lease was very hard to do. Not be­cause we want­ed many new fea­tures in­clud­ed (there are not that many, ac­tu­al­ly), but rather be­cause it was a bal­anc­ing act be­tween sta­bil­i­ty / back­wards com­pat­i­bil­i­ty and new "break­ing change" emerg­ing plat­forms (specif­i­cal­ly: Spring Boot 3, Hiber­nate 6 and their de­pen­den­cies on Jakar­taEE and very re­cent Java ver­sions).

We think we did a good job: just like the pre­vi­ous re­lease 5.0, this new re­lease can run on "good old" Java 8 for most mod­ules, ex­cept for Spring Boot 3 in­te­gra­tion (which re­quires Java 17 as per Spring Boot) and Hiber­nate 6. So if your ap­pli­ca­tion worked with re­lease 5.0 then it should still work, pro­vid­ed that you do the fol­low­ing:

Add ex­tra de­pen­den­cies ex­plic­it­ly to your POM

We now sup­port both javax and jakar­ta name­spaces for the Java en­ter­prise APIs, by of­fer­ing reg­u­lar jars as well as "jakar­ta" jars (with the cor­re­spond­ing clas­si­fi­er in the jar names). Th­ese jakar­ta jars are gen­er­at­ed at build time with the Eclipse trans­former util­i­ty.

In or­der to do this, we had to break the tran­si­tive de­pen­den­cy mech­a­nism (which, in­ci­den­tal­ly, also avoids pulling in vul­ner­a­ble 3rd par­ty code libs). So: ex­cept for Spring Boot 3 apps, this means that you will now have to add the fol­low­ing de­pen­den­cy to your pom file (or you risk fac­ing ClassNotFoundEx­cep­tions):

The tra­di­tion­al javax style

    <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>

The new jakar­ta style

      <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>

Over­ride the new JMS be­hav­iour to re­vert to pri­or re­lease be­hav­iour

We now sup­port JMS 2. This re­quired some changes to the JMS ses­sion cre­ation be­hav­iour, so if you rely on the "old" JMS be­hav­iour then set the fol­low­ing prop­er­ty on the AtomikosCon­nec­tionFac­to­ryBean:

     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 de­tails, see the javadoc of the AtomikosCon­nec­tionFac­to­ryBean class.

Drop any reapTime­out prop­er­ty

We've re­moved reap func­tion­al­i­ty from the pool, so re­move any reapTime­out prop­er­ty in your data­source or con­nec­tion fac­to­ry con­fig.

De­tailed re­lease notes

If you like the nit­ty grit­ty de­tails, then the fol­low­ing sec­tions are for you!

Fea­ture199869
Spring Boot 3 Starter

We added a starter for Spring Boot 3.

Tech­ni­cal de­tails

Spring Boot 3 has made a "big bang" up­grade to Jakar­ta EE and Java 17, with all com­pli­ca­tions in­volved. You can now use Atomikos with Spring Boot 3 by means of our new Spring Boot 3 starter mod­ule.

Changes im­pact­ing client API

Spring Boot 3 re­quires Java 17 or high­er, plus all Jakar­taEE li­braries (and for course Atomikos re­leas­es 6.0 or high­er). Note that this means you will also need Jakar­taEE JMS dri­vers, and Jakar­taEE per­sis­tence providers. Hur­ray.

You need the fol­low­ing de­pen­den­cy to use Spring Boot 3:

      <dependency>
         <groupId>com.atomikos</groupId>
         <artifactId>transactions-spring-boot3-starter</artifactId>
         <version>6.0.109</version>
      </dependency>

For the Jakar­taEE JMS and JTA APIs: we've added those to the Spring Boot 3 starter mod­ule al­ready - so you don't have to both­er.

Fea­ture197500
Sup­port Jakar­taEE li­braries and pack­ages

De­scrip­tion

We now also sup­port Jakar­taEE (in ad­di­tion to the "old" JEE with javax name­spaces).

Tech­ni­cal de­tails

All rel­e­vant mod­ules are now avail­able in both a tra­di­tion­al vari­ant and a Jakar­taEE vari­ant, the lat­ter gen­er­at­ed with the Eclipse trans­former util­i­ty dur­ing the build. Jakar­taEE jars car­ry the same name as their tra­di­tion­al coun­ter­parts, but have the ad­di­tion­al clas­si­fi­er "jakar­ta" in the jar file name to dis­tin­guish them.

The choice for this strat­e­gy was heav­i­ly dri­ven by our de­sire to still sup­port Java 8 ap­pli­ca­tions that can't up­grade to Java 17 or Jakar­taEE right now.

The pre­vi­ous state­ment prob­a­bly de­serves some ex­pla­na­tion: af­ter some ini­tial at­tempts it was painful­ly clear to us that up­grad­ing from Java 8 to Java 17 is noth­ing short of a night­mare.

[Oh and by the way, we fig­ure that this is the rea­son why ex­tend­ed sup­port for Java 8 is avail­able un­til 2030, the longest of all Java ver­sions at the time of pub­li­ca­tion. Yes, that means Java 8 should be sup­port­ed for longer than Java 17 - go fig­ure that!]

Our cho­sen ap­proach should al­low ex­ist­ing in­stal­la­tions to up­grade to our 6.0 re­lease with­out the need to up­grade to Jakar­taEE and/or Java 17 at the same time.

Past ex­pe­ri­ence with our cus­tomers has shown that even a "sim­ple" up­grade from Java 6 to Java 8 can be a huge road­block - es­pe­cial­ly if the de­vel­op­ment team is gone and only op­er­a­tions teams are left. So we pre­fer to keep up­grad­ing a seam­less and straight­for­ward process, with­out re­quir­ing need­less Java up­dates at the same time. We are sure that you will ap­pre­ci­ate that.

The "down­side" of this choice is that you can no longer count on tran­si­tive de­pen­den­cies as much as you did, be­cause many mod­ules now have 2 vari­ants avail­able (and hence the tran­si­tive de­pen­den­cies would not nec­es­sar­i­ly match the right vari­ant). While this may seem a dis­ad­van­tage, it ac­tu­al­ly in­creas­es se­cu­ri­ty be­cause there are no longer tran­si­tive de­pen­den­cies on 3rd par­ty jars ei­ther (so you avoid pulling in vul­ner­a­bil­i­ties).

So: you have to add some de­pen­den­cies man­u­al­ly that were tran­si­tive be­fore. But the ef­fort re­quired is sig­nif­i­cant­ly low­er than the ef­fort it would take to up­grade your code base to­wards Java 17 and Jakar­taEE all at once.

Changes im­pact­ing client API

As ex­plained in the up­grade sec­tion above: you need to de­clare some ex­tra de­pen­den­cies. Also, you have to be care­ful to use the right com­bi­na­tion of Jakar­ta-en­abled jars in your ap­pli­ca­tion. To this end, we have de­fined BOM files that list all the jars de­signed to work to­geth­er:

  • trans­ac­tions-es­sen­tials ver­sus trans­ac­tions-es­sen­tials-jakar­ta
  • ex­treme-trans­ac­tions ver­sus ex­treme-trans­ac­tions-jakar­ta

You can check these BOMs for in­spi­ra­tion on which jars to use / com­bine in your ap­pli­ca­tion. If you are cu­ri­ous where to find them: check groupId=com.atom­ikos and ar­ti­fac­tId=name_of_BOM_­file.

Fea­ture199608
Hiber­nate 6 sup­port

De­scrip­tion

You can now eas­i­ly use Hiber­nate 6 in com­bi­na­tion with our prod­uct!

Tech­ni­cal de­tails

Hiber­nate 6 is also in the Jakar­taEE camp, so of course you need Jakar­taEE sup­port to be able to use it. Well, as we've ex­plained above: we have done just that.

To use Hiber­nate 6, it suf­fices to use trans­ac­tions-hi­ber­nate4 in the jakar­ta flavour.

For a work­ing sam­ple: check the sup­plied ex­am­ples project called ex­am­ples-hi­ber­nate6 or see the sum­ma­ry POM snip­pet be­low.

Changes im­pact­ing client API

No real changes are need­ed, but you do have to add the cor­rect POM de­pen­den­cies:

      <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 Hiber­nate 6 de­pen­den­cies them­selves - but we'll leave that up to you...

Fea­ture85601
JMS 2.0 sup­port

De­scrip­tion

We now have (min­i­mal) sup­port for JMS 2.0.

Tech­ni­cal de­tails

As re­quired by Jakar­taEE and Spring Boot 3, we need­ed some sup­port for JMS 2.0. For the sake of re­leas­ing on time, this sup­port is only par­tial: we do not yet sup­port the new JMSCon­text API. Spring Boot 3 does not seem to need it, so that should be fine for now. At­tempt­ing to call any of the cre­ateCon­text meth­ods on the AtomikosCon­nec­tionFac­to­ryBean will throw Un­sup­port­edOper­a­tionEx­cep­tion.

Changes im­pact­ing client API

Ses­sion cre­ation be­hav­iour has changed due to the clar­i­fi­ca­tion of ses­sion cre­ation be­hav­iour in JMS 2.0 (which is in­com­pat­i­ble with what we had in pri­or re­leas­es). As you can see in the ta­ble be­low, the dif­fer­ences are in the com­bined in­ter­pre­ta­tion of:

  • a JTA trans­ac­tion be­ing present on the call­ing thread or not,
  • the val­ue set for lo­calTrans­ac­tionMode and
  • the val­ue of the ses­sionTrans­act­ed flag when cre­at­ing a ses­sion.

Pri­or to JMS 2.0, ses­sion cre­ation had some fuzzy bor­der cas­es where the in­ter­pre­ta­tion was left to the par­ty im­ple­ment­ing the specs (like Atomikos). In JMS 2.0 this has been ad­dressed. Need­less to say, the prob­a­bly of a per­fect match with our in­ter­pre­ta­tion was next to zero - so we had to make some changes.

To pre­serve com­pat­i­bil­i­ty your in­stances of AtomikosCon­nec­tionFac­to­ryBean now of­fer an ex­tra method setSes­sionCreationMode(int mode) which changes be­hav­iour as de­scribed be­low. The de­fault is val­ue 2 (JMS 2.0) so for com­pat­i­bil­i­ty with 5.0, try val­ue 1. For com­pat­i­bil­i­ty with pre-3.9 in­stal­la­tions, try val­ue 0.

Ses­sionCreationMode.JMS_2_0 (the de­fault as of re­lease 6.0), re­solv­ing to con­stant val­ue 2
ex­ist­ing JTA trans­ac­tion for thread lo­calTrans­ac­tionMode re­sult­ing ses­sion
true ig­nored XA ses­sion
false false XA ses­sion
false true non-XA ses­sion ac­cord­ing to ses­sionTrans­act­ed/ac­knowl­edgeMode pa­ra­me­ters
Ses­sionCreationMode.PRE_6_0 (op­tion­al, for back­ward com­pat­i­bil­i­ty) - re­solv­ing to con­stant val­ue 1
lo­calTrans­ac­tionMode ses­sionTrans­act­edFlag re­sult­ing ses­sion
false ig­nored XA ses­sion
true ig­nored non-XA ses­sion ac­cord­ing to ses­sionTrans­act­ed/ac­knowl­edgeMode pa­ra­me­ters
Ses­sionCreationMode.PRE_3_9 (op­tion­al, for back­ward com­pat­i­bil­i­ty and equiv­a­lent to ig­noreSes­sionTrans­act­edFlag = false) - re­solv­ing to con­stant val­ue 0
lo­calTrans­ac­tionMode ses­sionTrans­act­edFlag re­sult­ing ses­sion
false true XA ses­sion
oth­er oth­er non-XA ses­sion ac­cord­ing to ses­sionTrans­act­ed/ac­knowl­edgeMode pa­ra­me­ters

You can also find this in the javadoc of the AtomikosCon­nec­tionFac­to­ryBean.

Fea­ture20711
Sup­port for Trans­ac­tionSyn­chro­niza­tionRegistry

De­scrip­tion

We now of­fer an im­ple­men­ta­tion of Trans­ac­tionSyn­chro­niza­tionRegistry de­fined in the more re­cent JTA spec­i­fi­ca­tions.

Tech­ni­cal de­tails

You can use an in­stance of com.atom­ikos.icatch.jta.Trans­ac­tionSyn­chro­niza­tionRegistryImp con­tained in mod­ule trans­ac­tions-jta.jar.

Un­less you are a ven­dor of per­sis­tence providers, you prob­a­bly won't ever need this class so we'll keep the ex­pla­na­tion to a min­i­mum - since ven­dors of per­sis­tence providers al­ready know all there is to know.

Changes im­pact­ing client API

An ex­tra class avail­able in our dis­tri­b­u­tion, for you to use if you want to.

Fea­ture199530
Make the trans­ac­tion tem­plate thread-safe

De­scrip­tion

In­stances of com.atom­ikos.icatch.jta.tem­plate.Trans­ac­tionTem­plate are now tread-safe.

Tech­ni­cal de­tails

The first im­ple­men­ta­tions of our tem­plate were not in­tend­ed for thread­ed use cas­es. Based on cus­tomer feed­back, we have changed that - so you can now reuse the same in­stance in dif­fer­ent threads - just like Spring's tem­plate.

Changes im­pact­ing client API

In­stead of hav­ing to cre­ate mul­ti­ple tem­plate in­stances, you can now reuse the same in­stance in dif­fer­ent places of your code base. This should sim­pli­fy your con­fig­u­ra­tion and code base.

Fea­ture192016
Bet­ter sup­port for bor­rowCon­nec­tion time­outs in the pool

De­scrip­tion

We've im­proved the pool log­ic so that bor­row re­quests can bet­ter re­spect the time­out.

Tech­ni­cal de­tails

When a con­nec­tion is re­quest­ed and none is avail­able, new con­nec­tions would be cre­at­ed in the ap­pli­ca­tion's thread. In case of net­work is­sues, this would block the ap­pli­ca­tion's thread, pos­si­bly for much longer than the bor­rowCon­nec­tionTime­out set­ting would (and should) al­low. That's be­cause there is no easy way to in­ter­rupt a blocked IO re­quest.

We now im­proved this as fol­lows:

  • There is a sep­a­rate back­ground thread that grows the pool when need­ed.
  • The ap­pli­ca­tion's thread waits for this thread to grow the pool, but no longer than spec­i­fied by bor­rowCon­nec­tionTime­out.

Changes im­pact­ing client API

No real changes are need­ed, ex­cept that it should work bet­ter.

Fea­ture189885
Re­fac­tor shut­down: im­prove wait­ing for in-flight trans­ac­tions

De­scrip­tion

We have sim­pli­fied and im­proved the shut­down log­ic.

Tech­ni­cal de­tails

Shut­down used to wait for a time­out bound by the val­ue of com.atom­ikos.icatch.de­fault­_­max_wait­_­time_on_shut­down. Re­cov­ery it­self is al­ready bound by a dif­fer­ent pa­ra­me­ter: com.atom­ikos.icatch.de­fault­_­max_­time­out. The pre­vi­ous log­ic used to mix those two and the re­sults were not al­ways clear.

We have sim­pli­fied this to the fol­low­ing:

  • Shut­down waits for all ac­tive trans­ac­tions to fin­ish in the JVM.
  • Then it per­forms a re­cov­ery pass to clean up as much as pos­si­ble.
  • If both pre­vi­ous steps worked fine then there are no pend­ing trans­ac­tions and the trans­ac­tion log files can be delet­ed.
  • On the oth­er hand, if ei­ther step has is­sues then the trans­ac­tion log files have to be kept (we log a warn­ing for that).

Changes im­pact­ing client API

You no longer need com.atom­ikos.icatch.de­fault­_­max_wait­_­time_on_shut­down in your jta.prop­er­ties file. Be­ware that shut­down du­ra­tion is bound by the val­ue of com.atom­ikos.icatch.de­fault­_­max_­time­out - un­less you use the "forceShut­down" op­tion.

Fea­ture182107
Re­move user / pass­word prop­er­ties from Mes­sageDrivenCon­tain­er

De­scrip­tion

The user and pass­word prop­er­ties have been re­moved from com.atom­ikos.jms.ex­tra.Mes­sageDrivenCon­tain­er be­cause they were nev­er used any­way.

Tech­ni­cal de­tails

In­stances of this class del­e­gate to com.atom­ikos.jms.AtomikosCon­nec­tionFac­to­ryBean to cre­ate con­nec­tions. The lat­ter is also con­fig­ured with a user and pass­word, and those are the val­ues that are ac­tu­al­ly be­ing used.

As a re­sult, keep­ing two un­used prop­er­ties in the com.atom­ikos.jms.ex­tra.Mes­sageDrivenCon­tain­er class was con­fus­ing - so we have re­moved those.

Changes im­pact­ing client API

You need to re­move any ref­er­ences to these prop­er­ties from your con­fig­u­ra­tion.

Fea­ture199528
Drop reap­ing func­tion­al­i­ty from the pools

De­scrip­tion

We've re­moved the reap­ing func­tion­al­i­ty from the pools.

Tech­ni­cal de­tails

Reap­ing was when our pools would take away con­nec­tions that were be­ing held onto for too long.

His­tor­i­cal­ly, reap­ing func­tion­al­i­ty has caused more prob­lems / con­fu­sion than it solved. More­over, it was in­tend­ed to fix ap­pli­ca­tion-lev­el con­nec­tion leaks, mean­ing bugs in the ap­pli­ca­tion (as op­posed to bugs in our code base). We felt that be­came a source of need­less com­plex­i­ty.

We be­lieve that the cor­rect way of fix­ing ap­pli­ca­tion-lev­el con­nec­tion leaks is by fix­ing the ap­pli­ca­tion, rather than abrupt­ly reap­ing con­nec­tions away from that ap­pli­ca­tion. So our 6.0 re­lease seemed a good time to re­move that fea­ture.

Changes im­pact­ing client API

Re­move any ref­er­ences to reapTime­out from your con­fig­u­ra­tion.

Bug197505
Avoid that de­faults in the Spring Boot starter over­ride jta.prop­er­ties

Sever­i­ty:4
Af­fect­ed ver­sion(s):5.0.x

De­scrip­tion

You can now count on the prop­er­ty val­ues from jta.prop­er­ties to be tak­en into ac­count even with Spring Boot.

Tech­ni­cal de­tails

The Atomikos JTA prop­er­ties im­ple­men­ta­tion in our Spring Boot starter would de­fine de­fault val­ues for many prop­er­ties, mean­ing that their val­ue spec­i­fied jta.prop­er­ties would not be tak­en into ac­count. This has now been fixed.

Changes im­pact­ing client API

Your prop­er­ties spec­i­fied in jta.prop­er­ties should now work.

Bug197362
Clar­i­fy mes­sage if rest port not set in client

Sever­i­ty:1/2/3/4
Af­fect­ed ver­sion(s):5.0.x

De­scrip­tion

You can now count on a bet­ter er­ror mes­sage when the AtomikosRestPort URL is not set (for trans­ac­tions across re­mot­ing calls).

Tech­ni­cal de­tails

When the AtomikosRestPort URL was not set, the client tem­plate would re­port a mis­lead­ing mes­sage say­ing that there is no trans­ac­tion for the thread. In­stead, the root cause is a URL that is miss­ing - so we fixed that for you.

Changes im­pact­ing client API

None.

Bug197506
Sup­port di­a­mond case ar­chi­tec­tures for read­On­ly re­mot­ing

Sever­i­ty:4
Af­fect­ed ver­sion(s):5.0.x

De­scrip­tion

You can now use tran­si­tive read­On­ly re­mot­ing trans­ac­tions in all cas­es.

Tech­ni­cal de­tails

As out­lined in this GitHub is­sue there was a prob­lem with read­On­ly in­vo­ca­tions when:

  • the same shared ser­vice was called over dif­fer­ent paths, and
  • all in­vo­ca­tions were read­On­ly

This is known as a "di­a­mond case" be­cause the in­vo­ca­tion di­a­gram looks like a di­a­mond.

This is­sue has been fixed in the fol­low­ing way: our prod­uct will now avoid the read­On­ly op­ti­mi­sa­tion in this spe­cif­ic sce­nario. This is still cor­rect, at a mi­nor per­for­mance over­head in the ex­ot­ic cas­es where this does hap­pen.

Changes im­pact­ing client API

None.

Bug200555
Also close Cal­lable- and Pre­paredS­tate­ments when JDBC con­nec­tion is closed

Sever­i­ty:4
Af­fect­ed ver­sion(s):5.0.x

De­scrip­tion

Now you can close a JDBC con­nec­tion and also have the Cal­lable- and Pre­paredS­tate­ments closed au­to­mat­i­cal­ly.

Tech­ni­cal de­tails

When a JDBC con­nec­tion is closed by the ap­pli­ca­tion (re­turned to the pool) then the JDBC spec­i­fi­ca­tion re­quires all pend­ing state­ments to be closed as well.

We sup­port­ed this, but ap­par­ent­ly this was not done for all state­ment types. We fixed this now.

This is­sue is marked as sever­i­ty 4 (de­vel­op­ment use) be­cause we had no real bug re­ports from any cus­tomers. It was some­thing we no­ticed dur­ing a code re­view.

Changes im­pact­ing client API

None.

Bug197253
Sus­pend/re­sume should not change lo­cal sib­ling count

Sever­i­ty:2
Af­fect­ed ver­sion(s):5.0.x

De­scrip­tion

You can now use @Re­quiresNew with im­port­ed trans­ac­tions.

Tech­ni­cal de­tails

As ex­plained in this GitHub is­sue, there were prob­lems when a re­mote trans­ac­tion was im­port­ed and then sub­se­quent­ly called lo­cal log­ic that was marked with @Re­quiresNew. As re­quired by the spec­i­fi­ca­tion of @Re­quiresNew, this would sus­pend any ac­tive trans­ac­tion - and re­sume it lat­er.

Our code had a side ef­fect of sus­pend/re­sume that changed the lo­cal sib­ling count.

Si­b­ling counts help de­tect or­phaned in­vo­ca­tions (and their trans­ac­tion­al up­dates to per­sis­tent stor­age) that arise out of lost replies. For in­stance, con­sid­er this sce­nario with ser­vices A and B:

  1. A starts a trans­ac­tion.
  2. A calls B as part of that trans­ac­tion.
  3. B does work and re­turns a re­sult.
  4. A does not re­ceive the re­sult due to a net­work time­out (so B now has an or­phaned in­vo­ca­tion).
  5. A tries again, so B per­forms the changes again and re­turns a new re­sult (in the same trans­ac­tion).
  6. A com­mits the trans­ac­tion think­ing it only up­dat­ed B once.
  7. B com­mits the same trans­ac­tion with two sets of up­dates.

This risk here is the dif­fer­ent views of A and B re­gard­ing the scope of the trans­ac­tion: A thinks it com­mits one up­date to B, where­as B com­mits two dif­fer­ent up­dates. This can be a prob­lem for data con­sis­ten­cy, so we avoid this by keep­ing sib­ling counts at B and A. A con­structs its sib­ling count pic­ture with each re­sult it ac­tu­al­ly re­ceives with its replies from A. Be­fore com­mit, A pass­es on the "count" it has for in­vo­ca­tions at B, and if B finds that there is no match then it re­fus­es to com­mit.

This would avoid the prob­lem out­lined above, be­cause in step 4 ser­vice A will miss a count, so in step 6 ser­vice A will pass a count of 1 for ser­vice B, where­as B will see 2 and re­fus­es the com­mit process.

In short, sib­ling counts have their pur­pose. How­ev­er due to a bug, this was af­fect­ed by a sus­pend/re­sume at ser­vice B (when it has @Re­quiresNew log­ic in­side).

Changes im­pact­ing client API

You should now be able to con­fig­ure @Re­quiresNew on any ser­vice that needs it.

Bug197240
Al­low spring.jta prop­er­ties in Spring Boot starter

Sever­i­ty:4
Af­fect­ed ver­sion(s):5.0.x

De­scrip­tion

Any spring.jta prop­er­ties in Spring Boot should now be tak­en into ac­count.

Tech­ni­cal de­tails

After the Spring Boot team con­tributed the source code for their Atomikos starter we thought it was safer to ig­nore any prop­er­ties with the "lega­cy" pre­fix spring.jta.atom­ikos.prop­er­ties (in your ap­pli­ca­tion.prop­er­ties file for Spring Boot).

This has proven to con­fuse users, so we now take such spring.jta prop­er­ties into ac­count.

Changes im­pact­ing client API

Any spring.jta prop­er­ties in Spring Boot should now be tak­en into ac­count.

Bug200925
Im­prove han­dling of null xare­source

Sever­i­ty:3
Af­fect­ed ver­sion(s):3.9.x, 4.0.x, 5.0.x

De­scrip­tion

We've re­fined how we deal with lost XA con­nec­tions dur­ing the com­mit phase.

Tech­ni­cal de­tails

Some con­nec­tion is­sues would lead to need­less heuris­tic ex­cep­tions dur­ing com­mit, in par­tic­u­lar when the com­mit was 1-phase (where fail­ure to reach the back­end re­sults in re­source-in­ter­nal roll­back any­way).We have now re­fined this so there are no need­less heuris­tic ex­cep­tions any more in these cas­es. At the same time, we have also tried to min­imise the num­ber of cas­es where such con­nec­tion is­sues re­main.

Changes im­pact­ing client API

None.

Bug201164
Avoid Con­cur­ren­tMod­i­fi­ca­tionEx­cep­tion dur­ing trace log­ging in the pool

Sever­i­ty:4
Af­fect­ed ver­sion(s):5.0.x

De­scrip­tion

You can now use our pools with TRACE log­ging and get less ex­cep­tions.

Tech­ni­cal de­tails

The is­sue de­tails are de­scribed in this GitHub is­sue.

Changes im­pact­ing client API

None.

Is­sue201646
Spring Boot 2 starter: also add jta and jms ver­sions of Spring Boot's POM to the starter project

Sever­i­ty:4
Af­fect­ed ver­sion(s):6.0.x

De­scrip­tion

Un­like Spring Boot 3 sup­port, we did not yet add the JMS and JTA de­pen­den­cies in the Spring Boot 2 starter.

Tech­ni­cal de­tails

We still have to add the JMS and JTA de­pen­den­cies in the Spring Boot 2 starter. This is need­ed be­cause of the re­moval of tran­si­tive de­pen­den­cies. Un­til then, you will have to add them your­self.

Free Down­load

Bug181871
Avoid that Con­nec­tionPoolWithCon­cur­ren­tVal­i­da­tion grows be­yond maxPoolSize

Sever­i­ty:2
Af­fect­ed ver­sion(s):5.0.x

De­scrip­tion

We've port­ed a fix from our com­mer­cial re­lease that pre­vents the pool from ex­ceed­ing its maxPoolSize.

Tech­ni­cal de­tails

The con­cur­rent pool does not en­force syn­chro­niza­tion so when it:

  1. checks if the pool can grow and then
  2. ac­tu­al­ly grows it

... a dif­fer­ent thread may have done the same and the pool grows too much.

So­lu­tion: we've made growPool (with ex­ist­ing syn­chro­nized block) check maxSize again, and don't grow if al­ready at the max­i­mum.

Changes im­pact­ing client API

None.

Review: Going from Architect to Architecting: the Evolution of a Key Role
How evolutionary trends like agile and tooling support are changing the way architects should work

21 December 2022 | Guy Pardon | Review, Vision

This is our re­view of an ex­cel­lent ar­ti­cle pub­lished at In­foQ by some of our col­leagues at Red Hat. See the ref­er­ences sec­tion at the end for the orig­i­nal pub­li­ca­tion, but this overview aims to give you all of the in­sights and more in just a few lines of text. Where ap­plic­a­ble the con­tent has been com­ple­ment­ed with lessons learned from our own ex­pe­ri­ence...

Cybercrime and enterprise software
Supply chain attacks via public repositories

16 November 2022 | Guy Pardon | Review, Tech tips, Vision |

The bad guys are try­ing to get into your projects. What can you do to avoid pulling in bad code?

TransactionsEssentials 5.0.9
Release notes for 5.0.9

21 February 2022 | Guy Pardon | TransactionsEssentials

Fea­ture185294
Add gRPC sup­port and ex­am­ples

We now of­fer re­mot­ing sup­port for gRPC so your trans­ac­tions can span gRPC calls.

Tech­ni­cal de­tails

Some­times you may want com­mit or roll­back to ex­tend across one more more out­go­ing gRPC calls. This is now pos­si­ble.

See the ex­am­ple mod­ule: ex­am­ples-jta-grpc in the down­load for a work­ing sam­ple.

Changes im­pact­ing client API

New in­ter­cep­tors for your gRPC ar­chi­tec­ture are in­clud­ed.

Fea­ture188756
Add spring boot starter

Gen­er­ous­ly do­nat­ed by Piv­otal's Spring Boot team, we were able to add the Spring Boot starter mod­ule to our code base.

Tech­ni­cal de­tails

In­stead of adding Spring's starter mod­ule, you should now add "our" starter mod­ule to your Spring Boot project's pom.

In par­tic­u­lar, in­stead of spec­i­fy­ing:

   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jta-atomikos</artifactId>
   </dependency>

You should now spec­i­fy:

   <dependency>
      <groupId>com.atomikos</groupId>
      <artifactId>transactions-spring-boot-starter</artifactId>
      <version>5.0.9</version> <!-- or any later atomikos release that contains our starter module -->
   </dependency>

Ad­di­tion­al de­tails are here...

Changes im­pact­ing client API

No real API changes, only pom de­pen­den­cy changes.

Fea­ture189603
API ex­ten­sion to al­low trig­ger­ing re­cov­ery by the ap­pli­ca­tion

You can now ex­plic­it­ly trig­ger re­cov­ery in your ap­pli­ca­tion, via our API.

Tech­ni­cal de­tails

Re­cov­ery al­ready hap­pens pe­ri­od­i­cal­ly, in the back­ground. For big­ger clus­ters that con­nect to the same data­base (or oth­er shared re­source) this can cause a high load on the back­end, be­cause of many such back­ground threads hit­ting the back­end at the same time. This is es­pe­cial­ly true if most clus­ter nodes start up at the same time with the same con­fig­u­ra­tion for re­cov­ery, and are NOT us­ing LogCloud Doc­u­men­ta­tion. To al­le­vi­ate this, you can now have a bit more con­trol over when re­cov­ery hap­pens, like this:

import com.atomikos.icatch.RecoveryService;
import com.atomikos.icatch.config.Configuration;

boolean lax = true; //false to force recovery, true to allow intelligent mode
RecoveryService rs = Configuration.getRecoveryService();
rs.performRecovery(lax);

In or­der for this to work, make sure to set (in jta.prop­er­ties):

# set to Long.MAX_VALUE so background recovery is disabled
com.atomikos.icatch.recovery_delay=9223372036854775807L 

Changes im­pact­ing client API

We have added meth­ods on an ex­ist­ing API in­ter­face, which does not break ex­ist­ing clients.

Bug189264
Make sure timed out trans­ac­tions are cleaned up in the JVM

Sever­i­ty:2
Af­fect­ed ver­sion(s):5.0.x

De­scrip­tion

Timed out trans­ac­tions (in par­tic­u­lar heuris­tic haz­ard cas­es af­ter con­nec­tion is­sues) used to stay around in the JVM and kept on gen­er­at­ing time­out events. This has now been fixed.

Tech­ni­cal de­tails

Aban­doned trans­ac­tion in­stances now also stop any pend­ing threads that gen­er­ate time­out warn­ings. This pre­vents timed out trans­ac­tions from gen­er­at­ing end­less warn­ings that are no longer rel­e­vant.

Changes im­pact­ing client API

None.

Bug189263
JtaU­nawareThread­Lo­calCon­nec­tion: close should no­ti­fy pool for reuse

Sever­i­ty:2
Af­fect­ed ver­sion(s):5.0.x

De­scrip­tion

We op­ti­mised con­nec­tion pool ef­fi­cien­cy for non-JTA/XA aware use cas­es, so con­nec­tions are reused more ef­fi­cient­ly when wait­ing for busy con­nec­tions.

Tech­ni­cal de­tails

Pre­vi­ous­ly, wait­ing con­nec­tion re­quests were not no­ti­fied im­me­di­ate­ly when a busy con­nec­tion was be­ing closed (i.e., marked for reuse) by the ap­pli­ca­tion. This has now been fixed.

Changes im­pact­ing client API

None.

Bug188918
XaRe­sourceTrans­ac­tion: don't log ERROR when xare­source is null

Sever­i­ty:2
Af­fect­ed ver­sion(s):5.0

De­scrip­tion

In some rare cas­es the XARe­source used for com­mit­ting a trans­ac­tion af­ter pre­pare may be­come null (pre­sum­ably due to con­nec­tion er­rors, un­con­firmed though). In­stead of log­ging an er­ror (like we used to), we now trust back­ground-lev­el re­cov­ery to han­dle this - for which it was de­signed in the first place. This should avoid re­peat­ed the er­rors logged in such a case.

Tech­ni­cal de­tails

This "bug" would lead to mil­lisec­ond-lev­el re­peat­ed er­rors sim­i­lar to the fol­low­ing:

19/11/2020 15:20:43.467 [Atomikos:3321] ERROR com.atomikos.icatch.imp.CommitMessage - Unexpected error in commit
com.atomikos.icatch.HeurHazardException: XAResourceTransaction: 31302E3235342E3134362E3131302E746D313539353531353037383735393139373038:31302E3235342E3134362E3131302E746D373030333533: no XAResource to commit?
        at com.atomikos.datasource.xa.XAResourceTransaction.commit(XAResourceTransaction.java:529)
        at com.atomikos.icatch.imp.CommitMessage.send(CommitMessage.java:52)
        at com.atomikos.icatch.imp.CommitMessage.send(CommitMessage.java:23)
        at com.atomikos.icatch.imp.PropagationMessage.submit(PropagationMessage.java:67)
        at com.atomikos.icatch.imp.Propagator$PropagatorThread.run(Propagator.java:63)
        at com.atomikos.icatch.imp.Propagator.submitPropagationMessage(Propagator.java:42)
        at com.atomikos.icatch.imp.HeurHazardStateHandler.onTimeout(HeurHazardStateHandler.java:71)
        at com.atomikos.icatch.imp.CoordinatorImp.alarm(CoordinatorImp.java:650)
        at com.atomikos.timing.PooledAlarmTimer.notifyListeners(PooledAlarmTimer.java:95)
        at com.atomikos.timing.PooledAlarmTimer.run(PooledAlarmTimer.java:82)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
19/11/2020 15:20:53.468 [Atomikos:3321] ERROR com.atomikos.datasource.xa.XAResourceTransaction - XAResourceTransaction: 31302E3235342E3134362E3131302E746D313539353531353037383735393139373038:31302E3235342E3134362E3131302E746D373030333533: no XAResource to commit?

Now we no longer log these as er­rors, since we de­signed re­cov­ery to take care of ex­act­ly those kinds of ex­cep­tions.

Changes im­pact­ing client API

None.

Bug185591
Bug in JDBC state­ment proxy: callable state­ment

Sever­i­ty:4
Af­fect­ed ver­sion(s):5.0.x

De­scrip­tion

Fixed a bug that would hap­pen in cer­tain class load­ing en­vi­ron­ments and pre­vent­ed Cal­lableS­tate­ments from be­ing cre­at­ed.

Tech­ni­cal de­tails

Fixed a bug that would hap­pen in cer­tain class load­ing en­vi­ron­ments and pre­vent­ed Cal­lableS­tate­ments from be­ing cre­at­ed. This would lead to er­rors like this:

java.lang.ClassCastException: com.sun.proxy.$Proxy364 cannot be cast to java.sql.CallableStatement
            at com.atomikos.jdbc.internal.AbstractJdbcConnectionProxy.prepareCall(AbstractJdbcConnectionProxy.java:73)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            at com.atomikos.util.DynamicProxySupport.callProxiedMethod(DynamicProxySupport.java:162)
            at com.atomikos.util.DynamicProxySupport.invoke(DynamicProxySupport.java:116)
            at com.sun.proxy.$Proxy64.prepareCall(Unknown Source)

Changes im­pact­ing client API

None.

Bug183884
Re­mot­ing par­tic­i­pants do not re­spect com­mit or­der­ing

Sever­i­ty:2
Af­fect­ed ver­sion(s):5.0.x

De­scrip­tion

Re­mot­ing par­tic­i­pants now also re­spect com­mit or­der­ing so you can avoid is­sues with JMS no­ti­fi­ca­tions go­ing out be­fore the back­end data­bas­es are up to date.

Tech­ni­cal de­tails

Con­sid­er the fol­low­ing sce­nario for your mi­croser­vice:

1. re­ceive a JMS mes­sage 2. do a re­mote call to a dif­fer­ent mi­croser­vice that in turn up­dates a DB 3. send out a JMS "tick­et" mes­sage

Pre­vi­ous­ly, the JMS mes­sage (3) would be com­mit­ted first, when DB of the re­mote call in 2 still need­ed to com­mit. Re­cip­i­ents of (3) would some­times not see the up­dates in the DB when they re­ceive the mes­sage.

This has now been fixed, by in­cor­po­rat­ing the re­mote par­tic­i­pant of step 2 in the com­mit or­der.

Changes im­pact­ing client API

None.

Bug182578
NPE when check­ing class load­ers

Sever­i­ty:4
Af­fect­ed ver­sion(s):5.0.x

De­scrip­tion

We now check for null when adding class load­ers to cre­ate dy­nam­ic prox­ies.

Tech­ni­cal de­tails

At least one user has re­port­ed null is­sues when cre­at­ing a dy­nam­ic proxy, like this:

java.lang.NullPointerException: null
       at java.util.ArrayDeque.addLast(ArrayDeque.java:249) ~[?:1.8.0_251]
       at java.util.ArrayDeque.add(ArrayDeque.java:423) ~[?:1.8.0_251]
       at com.atomikos.util.DynamicProxySupport.getClassLoadersToTry(DynamicProxySupport.java:194) ~[?:?]
       at com.atomikos.util.DynamicProxySupport.createDynamicProxy(DynamicProxySupport.java:189) ~[?:?]
       at com.atomikos.jdbc.internal.AtomikosXAPooledConnection.doCreateConnectionProxy(AtomikosXAPooledConnection.java:119) ~[?:?]
       at com.atomikos.jdbc.internal.AtomikosXAPooledConnection.doCreateConnectionProxy(AtomikosXAPooledConnection.java:31) ~[?:?
       at com.atomikos.datasource.pool.AbstractXPooledConnection.createConnectionProxy(AbstractXPooledConnection.java:86) ~[?:?]
       at com.atomikos.datasource.pool.ConnectionPoolWithConcurrentValidation.concurrentlyTryToUse(ConnectionPoolWithConcurrentValidation.java:61) ~[?:?]
       at com.atomikos.datasource.pool.ConnectionPoolWithConcurrentValidation.retrieveFirstAvailableConnection(ConnectionPoolWithConcurrentValidation.java:43) ~[?:?]
       at com.atomikos.datasource.pool.ConnectionPool.retrieveFirstAvailableConnectionAndGrowPoolIfNecessary(ConnectionPool.java:140) ~[?:?]
       at com.atomikos.datasource.pool.ConnectionPool.findOrWaitForAnAvailableConnection(ConnectionPool.java:128) ~[?:?]
       at com.atomikos.datasource.pool.ConnectionPool.borrowConnection(ConnectionPool.java:119) ~[?:?]
       at com.atomikos.jdbc.internal.AbstractDataSourceBean.getConnection(AbstractDataSourceBean.java:371) ~[?:?]

We now fixed this by sim­ply check­ing if a class loader is not null be­fore at­tempt­ing to use it.

Changes im­pact­ing client API

None.

Bug185558
Avoid pass­ing all re­mote par­tic­i­pants as di­rect par­tic­i­pants for re­mot­ing trans­ac­tions

Sever­i­ty

2

Af­fect­ed ver­sions

5.0.x

De­scrip­tion

We used to pass all re­mote par­tic­i­pants as di­rect par­tic­i­pants, mean­ing that two-phase com­mit would some­times be re­peat­ed and fail. This would par­tic­u­lar­ly be the case in "di­a­mond" calls - or also in deep­er call hi­er­ar­chies of more than one lev­el down.

Tech­ni­cal de­tails

Con­sid­er a re­mot­ing client ser­vice A call­ing an­oth­er re­mot­ing ser­vice B.

For re­mot­ing we dis­tin­guish be­tween di­rect par­tic­i­pants (i.e., end­points at B to be in­clud­ed for two-phase com­mit at A) and in­di­rect par­tic­i­pants (i.e., URIs added as meta­da­ta only for check­ing or­phaned calls).

The class De­fault­Im­port­ingTrans­ac­tionMan­ag­er in mod­ule trans­ac­tions-re­mot­ing used to pass all its re­mote par­tic­i­pants as di­rect par­tic­i­pants, i.e. par­tic­i­pants to be in­clud­ed in the re­mot­ing's two-phase com­mit set. In par­tic­u­lar for di­a­mond-shaped calls (A calls B and C, and both B and C in turn call D) this would give re­peat­ed two-phase com­mit calls to D, be­cause A would in­cor­rect­ly re­ceive D as a di­rect par­tic­i­pant via the call hi­er­ar­chies of both B and C.

We fixed this, and for this spe­cif­ic case A would now only re­ceive 2 di­rect par­tic­i­pants: B and C.

This fix also re­solves an is­sue with a sim­pler call stack: A → B → C, where C would also be called for two-phase com­mit by both A and B. The is no longer the case.

Changes im­pact­ing client API

None.

Spe­cial thanks

Thanks to @bean­ww for re­port­ing this on GitHub.

Bug185557
Avoid app-serv­er thread leak when de­ployed in servers like Tom­cat

Sever­i­ty

3

Af­fect­ed ver­sions

4.0.x, 5.0.x

De­scrip­tion

Serv­er-side (Tom­cat) in­te­gra­tion cre­at­ed threads for in­di­vid­ual trans­ac­tions (at web app lev­el) with the class loader of the web ap­pli­ca­tion. This would cause (Tom­cat) warn­ings when the web ap­pli­ca­tion is stopped be­cause those threads will hang around in the thread pool.

So­lu­tion: we now start new threads with the serv­er-lev­el class loader.

Tech­ni­cal de­tails

If you have the trans­ac­tion core at the serv­er lev­el (in the serv­er's class­path) then in­di­vid­ual trans­ac­tions start­ed in the web ap­pli­ca­tion will use the serv­er-lev­el thread pool of Atomikos (named com.atom­ikos.thread.TaskMan­ag­er).

This would typ­i­cal­ly give warn­ings (in Tom­cat) like this when the web ap­pli­ca­tion is be­ing shut down:

WARNING [http-nio-3030-exec-6] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [mywebapp] appears to have started a thread named [Atomikos:2] but has failed to stop it. This is very likely to create a memory leak.

That's be­cause the serv­er-side thread pool threads used to be cre­at­ed with the web ap­pli­ca­tion's class loader.

This also hap­pened for our built-in Tom­cat in­te­gra­tion (since it is con­fig­ured at the serv­er-lev­el).

We now cre­ate those threads with the thread pool's class­loader in­stead. When con­fig­ured at the serv­er lev­el, this will no longer be the ap­pli­ca­tion's class loader and that seems to pre­vent this prob­lem.

Changes im­pact­ing client API

None.

Spe­cial thanks

Spe­cial thanks to @jjim­jam for re­port­ing this on GitHub, and thanks also to the Jet­ty - Webtide team for ex­tra in­put.

Bug189921
Avoid that ex­cep­tions when writ­ing a check­point need­less­ly cor­rupt the trans­ac­tion log

Sever­i­ty

2

Af­fect­ed ver­sions

4.0.x, 5.0.x

De­scrip­tion

You now no longer get "Log cor­rupt­ed - restart JVM" ex­cep­tions af­ter you in­ter­rupt a thread that is writ­ing to the trans­ac­tion log file, or af­ter any oth­er ex­cep­tion that make a log check­point fail.

Tech­ni­cal de­tails

Any ex­cep­tions dur­ing a check­point (such as when a thread was in­ter­rupt­ed dur­ing trans­ac­tion log file I/O) would lead to a gener­ic ex­cep­tion han­dling block in our com.atom­ikos.re­cov­ery.fs.CachedRe­pos­i­to­ry class, leav­ing the in­stance in an in­valid state:

2021-03-01 16:15:56.662 ERROR 41669 --- [pool-1-thread-1] c.a.recovery.fs.FileSystemRepository     : Failed to write checkpoint

java.nio.channels.ClosedByInterruptException: null
   at java.nio.channels.spi.AbstractInterruptibleChannel.end(AbstractInterruptibleChannel.java:202) ~[na:1.8.0_192]
   at sun.nio.ch.FileChannelImpl.force(FileChannelImpl.java:392) ~[na:1.8.0_192]
   at com.atomikos.recovery.fs.FileSystemRepository.writeCheckpoint(FileSystemRepository.java:196) ~[transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.recovery.fs.CachedRepository.performCheckpoint(CachedRepository.java:84) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.recovery.fs.CachedRepository.put(CachedRepository.java:77) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.recovery.fs.OltpLogImp.write(OltpLogImp.java:46) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.persistence.imp.StateRecoveryManagerImp.preEnter(StateRecoveryManagerImp.java:51) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.finitestates.FSMImp.notifyListeners(FSMImp.java:164) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.finitestates.FSMImp.setState(FSMImp.java:251) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.CoordinatorImp.setState(CoordinatorImp.java:284) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.CoordinatorStateHandler.commitFromWithinCallback(CoordinatorStateHandler.java:346) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.ActiveStateHandler$6.doCommit(ActiveStateHandler.java:273) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.CoordinatorStateHandler.commitWithAfterCompletionNotification(CoordinatorStateHandler.java:587) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.ActiveStateHandler.commit(ActiveStateHandler.java:268) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.CoordinatorImp.commit(CoordinatorImp.java:550) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.CoordinatorImp.terminate(CoordinatorImp.java:682) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.CompositeTransactionImp.commit(CompositeTransactionImp.java:279) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.jta.TransactionImp.commit(TransactionImp.java:168) [transactions-jta-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.jta.TransactionManagerImp.commit(TransactionManagerImp.java:428) [transactions-jta-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.jta.UserTransactionManager.commit(UserTransactionManager.java:160) [transactions-jta-5.0.9-SNAPSHOT.jar:na]
   at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1035) [spring-tx-5.2.5.RELEASE.jar:5.2.5.RELEASE]
   at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743) [spring-tx-5.2.5.RELEASE.jar:5.2.5.RELEASE]
   at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711) [spring-tx-5.2.5.RELEASE.jar:5.2.5.RELEASE]
   at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:152) [spring-tx-5.2.5.RELEASE.jar:5.2.5.RELEASE]
   at com.example.atomikos.AtomikosApplicationTests.lambda$4(AtomikosApplicationTests.java:78) [test-classes/:na]
   at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_192]
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_192]
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_192]
   at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_192]

Later re­quests try­ing to read from the trans­ac­tion logs would get sys­tem­at­ic cor­rup­tion er­rors like this:

com.atomikos.recovery.LogReadException: Log corrupted - restart JVM
   at com.atomikos.recovery.fs.CachedRepository.assertNotCorrupted(CachedRepository.java:137) ~[transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.recovery.fs.CachedRepository.findAllCommittingCoordinatorLogEntries(CachedRepository.java:145) ~[transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.recovery.fs.RecoveryLogImp.getExpiredPendingCommittingTransactionRecordsAt(RecoveryLogImp.java:52) ~[transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.RecoveryDomainService.performRecovery(RecoveryDomainService.java:76) ~[transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.RecoveryDomainService$1.alarm(RecoveryDomainService.java:55) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.timing.PooledAlarmTimer.notifyListeners(PooledAlarmTimer.java:101) [atomikos-util-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.timing.PooledAlarmTimer.run(PooledAlarmTimer.java:88) [atomikos-util-5.0.9-SNAPSHOT.jar:na]
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_192]
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_192]
   at java.lang.Thread.run(Thread.java:748) [na:1.8.0_192]

This has now been fixed.

Changes im­pact­ing client API

None.

About Sever­i­ty

The sever­i­ty lev­els we use are de­fined in our sup­port terms and con­di­tions.

Corporate Information

Atomikos Corporate Headquarters
Hoveniersstraat, 39/1, 2800
Mechelen, Belgium

Contact Us

Copyright 2026 Atomikos BVBA | Our Privacy Policy
This page was cached on 24 May 2026 - 00:09.
By using this site you agree to our cookies. More info. That's Fine