Skip to main content
Version: 4.6

Transaction Guide

Anyone working with multiple datasources eventually runs into transactions. This chapter does not simply list "the available options" โ€” it helps you pick the right one in 30 seconds.

Understand one fact firstโ€‹

Once a native Spring transaction is open, the whole thread keeps getting the same Connection.

Datasource switching relies on a key in a ThreadLocal, while @Transactional binds the connection to the thread. Together this means: after the transaction starts, neither the switching annotation nor a manual push has any effect any more.

This is not a bug; it is the inevitable consequence of the relational transaction model combined with "one connection per call". Once you understand this, every option below becomes easy to choose.

Decision treeโ€‹

Do you need a transaction?
โ””โ”€ no โ†’ do nothing

Yes. Will you switch to another database inside the transaction?
โ”œโ”€ no (single database reads/writes only) โ†’ use the native Spring @Transactional (together with @DS)
โ”‚
โ””โ”€ yes
โ”œโ”€ within the same application process โ†’ use @DSTransactional
โ””โ”€ across services / processes โ†’ use Seata (AT or XA)

Comparing the optionsโ€‹

OptionUse caseExternal dependencyCross-serviceConsistency
@Transactional + @DSsingle-database transactions that never switch inside the transactionnonenostrong (guaranteed by the database)
@DSTransactionalspanning several databases inside one monolithnonenobest-effort (see the note below)
Seata ATacross microservicesSeata Serveryeseventual, with automatic compensation
Seata XAcross-service with strong consistencySeata Serveryesstrong, lower performance
Atomikos XAstandard XA inside a single processAtomikosnostrong
@DSTransactional is not strict 2PC

What @DSTransactional does is: open a local transaction for each database involved, all registered under the same XID, then commit database by database when the business method returns normally, and roll back database by database when it throws.

The rollback is best-effort โ€” if one database fails to roll back, that does not stop the others from rolling back. Committing is likewise sequential โ€” if a database fails during the commit phase, the databases committed earlier cannot be rolled back any more.

So it fits "a monolith where cross-database consistency does not have to be 100% airtight". For financial-grade strong consistency, go for XA.

In this chapterโ€‹

Further readingโ€‹