Skip to content
Kafka Is FunProgress

Production Patterns · Intermediate

Transactional Kafka Producer

Kafka transactions enable atomic writes across multiple topics/partitions. Required for exactly-once when combining multiple Kafka writes with a single business operation.

application.yml (transaction config)yaml
spring:
  kafka:
    producer:
      transaction-id-prefix: order-service-tx-
      # When transaction-id-prefix is set, Spring creates KafkaTransactionManager
TransactionalOrderService.javajava
@Service
@Slf4j
public class TransactionalOrderService {

    private final KafkaTemplate<String, Object> kafkaTemplate;

    // Option 1: @Transactional (Spring coordinates Kafka + DB transaction)
    @Transactional("kafkaTransactionManager")
    public void processOrderWithEvents(Order order) {
        // Both sends are atomic — either both commit or both abort
        kafkaTemplate.send("orders.order.created",
            order.getId(), new OrderCreatedEvent(order));
        kafkaTemplate.send("inventory.reservation.requested",
            order.getId(), new ReservationRequest(order));
        // If exception thrown here, both messages are ABORTED
    }

    // Option 2: Explicit transaction control
    public void processWithExplicitTx(Order order) {
        kafkaTemplate.executeInTransaction(operations -> {
            operations.send("orders.order.created", order.getId(), new OrderCreatedEvent(order));
            operations.send("payments.payment.requested", order.getId(), new PaymentRequest(order));
            return true;
        });
    }

    // Option 3: Chained Kafka + DB transaction (consume-transform-produce)
    @Transactional("chainedKafkaTransactionManager")
    @KafkaListener(topics = "orders.order.created")
    public void consumeAndProduce(OrderCreatedEvent event) {
        // Save to DB + produce output event are atomic
        orderRepository.save(new Order(event));
        kafkaTemplate.send("orders.order.processed", event.getOrderId(), new ProcessedEvent(event));
    }
}