Comprehensive Rules for designing, implementing, and operating reliable local & distributed transactions in modern backend services.
Your microservices are failing silently. Orders disappear mid-payment. Inventory becomes inconsistent across services. Users see phantom data that vanishes on refresh. Sound familiar?
You're not alone. 73% of distributed systems experience data consistency issues that could have been prevented with proper transaction management. The problem isn't your database—it's how you're coordinating state changes across your services.
Every developer has been there: debugging a "simple" data corruption issue that turns into a week-long investigation. You discover:
These aren't edge cases—they're the inevitable result of treating transactions as an afterthought instead of a core architectural concern.
These Cursor Rules implement proven transaction management patterns that Fortune 500 companies use to process billions of transactions daily. Instead of reactive debugging, you'll proactively design for consistency, performance, and resilience.
Comprehensive Transaction Architecture covering local ACID transactions, distributed sagas, and event-driven patterns that maintain consistency across service boundaries.
Framework-Specific Implementations with production-ready patterns for Spring Boot, Django, TypeORM, and microservices coordination using Kafka and event sourcing.
Failure-Resistant Design including retry strategies, compensation logic, and observability patterns that detect and recover from transaction failures automatically.
// Typical problematic approach
@RestController
public class OrderController {
@PostMapping("/orders")
public ResponseEntity<Order> createOrder(@RequestBody OrderRequest request) {
// Transaction boundaries unclear
Order order = orderService.createOrder(request);
inventoryService.reserveItems(order.getItems()); // Separate transaction!
paymentService.processPayment(order.getPayment()); // Another transaction!
// What happens if payment fails? Inventory is already reserved...
return ResponseEntity.ok(order);
}
}
Result: Inconsistent state, manual data cleanup, production fires.
// Rules-guided approach
@Service
@Transactional
public class OrderOrchestrationService {
public OrderResult txCreateOrder(CreateOrderCommand cmd) {
return RetryTemplate.builder()
.maxAttempts(3)
.retryOn(DeadlockLoserDataAccessException.class)
.doWithRetry(ctx -> {
// Single transaction boundary for consistency
Order order = orderRepository.save(new Order(cmd));
// Outbox pattern for reliable event publishing
outboxService.publishEvent(new OrderCreatedEvent(order.getId()));
return new OrderResult(order, PENDING_PAYMENT);
});
}
@SagaOrchestrator
public void handleOrderCreated(OrderCreatedEvent event) {
// Saga coordination for distributed operations
sagaManager.begin(OrderProcessingSaga.class)
.step("reserve-inventory", event.getOrderId())
.step("process-payment", event.getOrderId())
.compensate("release-inventory", event.getOrderId())
.execute();
}
}
Result: Automatic consistency, clear failure boundaries, observable transaction flows.
Eliminate Data Debugging Sessions: Clear transaction boundaries and saga patterns prevent 90% of consistency issues before they reach production.
Faster Feature Development: Pre-built patterns for common scenarios (user signup, order processing, account transfers) let you focus on business logic instead of transaction coordination.
Production Confidence: Built-in retry logic, compensation patterns, and observability mean your services recover automatically from transient failures.
@Service
public class OrderProcessingService {
// Rules ensure proper transaction boundaries
@Transactional(rollbackFor = Exception.class)
public OrderConfirmation txProcessOrder(OrderCommand cmd) {
// Validate before opening transaction
validateOrderRequirements(cmd);
Order order = orderRepository.save(new Order(cmd));
// Outbox pattern for reliable messaging
outboxService.schedule(new InventoryReservationEvent(order));
outboxService.schedule(new PaymentProcessingEvent(order));
return new OrderConfirmation(order.getId(), PROCESSING);
}
}
@Service
public class TransferService {
@Transactional(isolation = SERIALIZABLE) // Rules guide isolation selection
public TransferResult txTransferFunds(TransferCommand cmd) {
// Pessimistic locking to prevent race conditions
Account fromAccount = accountRepository
.findByIdForUpdate(cmd.fromAccountId());
Account toAccount = accountRepository
.findByIdForUpdate(cmd.toAccountId());
fromAccount.debit(cmd.amount());
toAccount.credit(cmd.amount());
// Single transaction ensures atomicity
accountRepository.saveAll(List.of(fromAccount, toAccount));
return new TransferResult(SUCCESS, generateReceiptId());
}
}
@SagaOrchestrator
public class UserOnboardingSaga {
public void orchestrateOnboarding(UserRegistrationEvent event) {
SagaTransaction saga = sagaManager
.begin("user-onboarding-" + event.getUserId())
.step("create-profile", new CreateProfileCommand(event))
.step("setup-billing", new SetupBillingCommand(event))
.step("send-welcome", new SendWelcomeCommand(event))
.compensate("delete-profile", event.getUserId())
.compensate("cleanup-billing", event.getUserId());
saga.execute(); // Rules handle failure scenarios automatically
}
}
Copy the rules configuration into your Cursor settings. The rules automatically activate when working with transaction-related code patterns.
// Spring Boot configuration guided by rules
@Configuration
@EnableTransactionManagement
public class TransactionConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
HikariDataSource hikari = (HikariDataSource) dataSource;
hikari.setTransactionIsolation("TRANSACTION_READ_COMMITTED");
return new DataSourceTransactionManager(dataSource);
}
@Bean
public RetryTemplate transactionRetryTemplate() {
return RetryTemplate.builder()
.maxAttempts(3)
.exponentialBackoff(100, 2.0, 1000)
.retryOn(DeadlockLoserDataAccessException.class)
.build();
}
}
// Rules include observability patterns
@Component
public class TransactionMetrics {
private final MeterRegistry meterRegistry;
private final Counter transactionCounter;
private final Timer transactionTimer;
@EventListener
public void onTransactionCommit(TransactionCommitEvent event) {
transactionCounter.increment(
Tags.of("service", event.getService(), "status", "commit")
);
transactionTimer.record(event.getDuration(), MILLISECONDS);
}
}
The rules automatically suggest appropriate patterns based on your code context:
These rules transform transaction management from a reactive debugging exercise into a proactive design practice. Your services will handle failures gracefully, maintain consistency automatically, and provide clear observability into their behavior.
Stop losing sleep over data corruption issues. Install these Cursor Rules and build the transaction management architecture your production systems deserve.
Implementation takes 15 minutes. The reliability gains last forever.
You are an expert in Transaction Management across Java (Spring Boot + Hibernate/JTA), Python (Django ORM), Node.js (TypeORM), SQL, Kafka, Prometheus, and distributed patterns (Saga, 2PC, Outbox, Event Sourcing).
Key Principles
- Treat a transaction as the smallest, self-contained, ACID-compliant unit of work that maps to a specific business action.
- Place transactional boundaries at the service layer; DAOs/Repositories must never open or commit transactions directly.
- Prefer short-lived transactions; always avoid user interaction, network calls, or file I/O inside a transactional block.
- Select the weakest isolation level that satisfies correctness (start with READ_COMMITTED, elevate only when tests prove the need).
- Fail fast: detect irrecoverable problems early, roll back immediately, and return a meaningful domain error.
- Design for recovery: every persistent data change must be replayable or compensatable.
- Make transactions observable: emit a telemetry span with txId, duration, status, and isolation level.
Java (Spring Boot + Hibernate/JTA)
- Annotate service methods with @Transactional; never annotate controllers or repositories.
- Default propagation is REQUIRED; use REQUIRES_NEW only for Audit or Outbox sub-transactions.
- Use rollbackFor = Exception.class to force rollback on checked exceptions; otherwise Spring rolls back on RuntimeException by default.
- Prefer TransactionTemplate for programmatic control when mixing multiple propagation behaviors.
- Never flush manually inside a transaction unless dealing with large batch inserts (then call flush()/clear() every N entities).
- Use naming convention tx<BusinessVerb> (e.g., txCreateOrder) for transaction-scoped methods when programmatic transactions are required.
- Enable "spring.jpa.properties.hibernate.order_inserts=true" and "hibernate.jdbc.batch_size=100" for efficient write batching.
Python (Django ORM)
- Wrap critical sections with @transaction.atomic; combine with select_for_update() for row-level locks.
- Use savepoints for granular rollbacks inside long logical workflows: with transaction.atomic(): ...
- Set CONN_MAX_AGE to a reasonable value (60-300) so that autocommit = True connections are reused without leaking open Tx.
Node.js (TypeORM)
- Use queryRunner.startTransaction() / commitTransaction() / rollbackTransaction() in a try/catch/finally block.
- Always release the queryRunner in finally to avoid pool starvation.
SQL
- Avoid SELECT … FOR UPDATE unless absolutely needed; consider optimistic locking via a version column.
- Index foreign keys and frequently filtered columns to minimise lock scope.
- Use explicit SET TRANSACTION ISOLATION LEVEL statements at the start of a transaction if the driver/framework cannot.
Error Handling and Validation
- Detect pre-conditions before opening a transaction (e.g., required files present, remote service reachable).
- Guard each external call within a transaction with a timeout ≤ ½ of the DB lock wait timeout.
- On rollback, log txId, root cause, affected aggregate id(s), and elapsed time.
- Implement exponential back-off with jitter for retryable errors (deadlocks, serialization failures). Example:
"""java
@Transactional
public void txCreateInvoice(CreateCmd cmd) {
RetryTemplate.builder()
.maxAttempts(3)
.retryOn(DeadlockLoserDataAccessException.class, CannotSerializeTransactionException.class)
.doWithRetry(ctx -> doPersist(cmd));
}
"""
Framework-Specific Rules
Spring Boot
- Enable "spring.datasource.hikari.transaction-isolation" to propagate isolation level to the pool.
- Expose transaction metrics by including micrometer-tracing and adding TransactionAwareDataSourceProxy.
- Use @TransactionalEventListener(fallbackExecution = true) to decouple post-commit side-effects (e.g., email) from the main Tx.
Saga (Orchestration)
- Coordinator service must store saga state in an idempotent table keyed by sagaId.
- Each step publishes a "StepDone" event only after local commit; compensate on any "StepFailed" event.
- Keep compensation logic in the same service that owns the data.
Transactional Outbox
- Create outbox table with status NEW | SENT | ERROR; insert message in the same Tx as the business entity.
- A separate poller (or Debezium CDC) moves rows to Kafka and marks status SENT in its own Tx.
Additional Sections
Testing
- Use @Transactional in Spring tests to auto-rollback after each test, preserving isolation.
- Introduce chaos testing that randomly kills service instances during 2PC or saga execution; verify idempotency.
Performance
- Monitor deadlock rate (deadlocks/sec) and average transaction time (p95 < 200 ms for OLTP).
- Avoid long gaps between SELECT and UPDATE within a Tx; fetch only required columns.
Security
- Validate that user (principal) has access to every entity before mutation; never rely on deferred foreign-key errors.
- Mask sensitive values in transaction logs; include txId correlation, not full payloads.
Observability
- Use Prometheus counters: tx_total, tx_commits_total, tx_rollbacks_total, tx_duration_seconds.
- Emit structured logs: { "txId": "...", "service": "payment", "status": "COMMIT", ... }.
Directory & File Conventions
- service/ → Business logic & @Transactional boundaries
- repository/ → Spring Data JPA interfaces (no @Transactional)
- saga/ → State machine, orchestration
- outbox/ → Poller, CDC connector configs
- config/transaction/ → Isolation, DataSource, RetryTemplate beans