Transactions
The Quarkus Morphium extension provides declarative transaction support via the
@MorphiumTransactional annotation. On success the transaction is committed; on any
exception it is rolled back and the exception is re-thrown.
Replica-Set Requirement
|
MongoDB multi-document transactions require a replica set (or sharded cluster). A standalone MongoDB instance does not support transactions. Dev Services starts MongoDB as a single-node replica set by default, so transactions work out of the box. See Dev Services for details. |
@MorphiumTransactional
Annotate any CDI bean method to wrap it in a Morphium transaction:
import de.caluga.morphium.Morphium;
import de.caluga.morphium.quarkus.transaction.MorphiumTransactional;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@ApplicationScoped
public class OrderService {
@Inject Morphium morphium;
@MorphiumTransactional
public void placeOrder(Order order, Payment payment) {
morphium.store(order);
morphium.store(payment);
// auto-commit on success, auto-rollback on exception
}
}
The annotation may also be placed on a class to apply it to all business methods.
Transaction Lifecycle
The interceptor executes at priority PLATFORM_BEFORE + 200 and follows this sequence:
-
morphium.startTransaction() -
Execute the business method
-
Fire
BEFORE_COMMITCDI event -
morphium.commitTransaction() -
Fire
AFTER_COMMITCDI event
On exception:
-
morphium.abortTransaction() -
Fire
AFTER_ROLLBACKCDI event (with the causingException) -
Re-throw the exception
Transaction Lifecycle Events
Use @Observes with the @MorphiumTxPhase qualifier to react to transaction phases:
import de.caluga.morphium.quarkus.transaction.*;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import org.jboss.logging.Logger;
import static de.caluga.morphium.quarkus.transaction.MorphiumTransactionEvent.Phase.*;
@ApplicationScoped
public class AuditObserver {
private static final Logger LOG = Logger.getLogger(AuditObserver.class);
void afterCommit(@Observes @MorphiumTxPhase(AFTER_COMMIT) MorphiumTransactionEvent e) {
// e.g. publish a domain event
}
void afterRollback(@Observes @MorphiumTxPhase(AFTER_ROLLBACK) MorphiumTransactionEvent e) {
LOG.warn("Transaction rolled back", e.getFailure());
}
}
| Phase | When it fires | getFailure() |
|---|---|---|
|
After the business method succeeds, before |
|
|
After |
|
|
After |
The causing |
CosmosDB Compatibility
When running against Azure CosmosDB, Morphium auto-detects the backend via the
hello handshake. Because CosmosDB does not support multi-document transactions,
@MorphiumTransactional gracefully degrades: the interceptor skips transaction
wrapping and executes the method directly.
A single WARN-level message is logged at application startup if CosmosDB is detected, and each subsequent invocation is logged at DEBUG level:
WARN CosmosDB detected — @MorphiumTransactional methods will execute WITHOUT
transaction wrapping. Individual ops remain atomic; multi-document rollback is unavailable.
|
On CosmosDB, lifecycle events ( |
Testing Transactions
To test @MorphiumTransactional methods, you need a replica set. Dev Services starts one
by default, so no extra configuration is needed:
@QuarkusTest
class OrderServiceTest {
@Inject OrderService orderService;
@Inject Morphium morphium;
@BeforeEach
void setUp() {
morphium.dropCollection(Order.class);
morphium.dropCollection(Payment.class);
}
@Test
void placeOrderCommitsOnSuccess() {
orderService.placeOrder(new Order("A1"), new Payment(42.0));
assertThat(morphium.createQueryFor(Order.class).countAll()).isEqualTo(1);
assertThat(morphium.createQueryFor(Payment.class).countAll()).isEqualTo(1);
}
@Test
void placeOrderRollsBackOnFailure() {
assertThrows(RuntimeException.class, () ->
orderService.placeOrderThatFails(new Order("A2"), new Payment(0.0)));
assertThat(morphium.createQueryFor(Order.class).countAll()).isEqualTo(0);
}
}
The InMemDriver does not support true multi-document transactions. Use Dev Services
(replica set is enabled by default) for transaction testing. See Testing
for more strategies.
|