Шаблон транзакционного исходящего журнала
Узнайте, как шаблон транзакционного исходящего журнала надёжно связывает транзакцию базы данных с публикацией в Kafka, устраняя несогласованность двойной записи в Spring Boot.
«Шаблон транзакционного исходящего журнала» — бесплатный урок Advanced Spring Boot 4: Event-Driven Architecture (Kafka) на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Advanced Spring Boot 4: Event-Driven Architecture (Kafka), и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Advanced Spring Boot 4: Event-Driven Architecture (Kafka) содержит 4 уроков всего.
Части этого урока еще не переведены и отображаются на английском.
The Dual-Write Problem
A common bug: a service updates its database and publishes a Kafka event in two separate operations. If one succeeds and the other fails, the system becomes inconsistent.
The transactional outbox pattern eliminates this risk.
Core Idea
Instead of publishing directly, write the event into an outbox table within the same database transaction as your business change.
A separate process then reads the outbox and publishes to Kafka.
The Outbox Table
The outbox table stores serialized events plus metadata.
CREATE TABLE outbox (
id UUID PRIMARY KEY,
aggregate_type VARCHAR(255),
aggregate_id VARCHAR(255),
event_type VARCHAR(255),
payload JSONB,
created_at TIMESTAMP DEFAULT now(),
published BOOLEAN DEFAULT false
);Writing in One Transaction
Both the domain entity and the outbox row are saved inside one @Transactional method, so they commit or roll back together.
@Transactional
public void placeOrder(Order order) {
orderRepository.save(order);
outboxRepository.save(OutboxEvent.from(order));
}Atomicity Guarantee
Because both writes share the database transaction, there is no window where the order exists without its event recorded. This is the key correctness property.
The Relay Process
A background relay polls unpublished outbox rows and sends them to Kafka, marking them published on success.
@Scheduled(fixedDelay = 500)
public void relay() {
for (OutboxEvent e : outboxRepository.findUnpublished()) {
kafkaTemplate.send(e.getTopic(), e.getPayload());
e.markPublished();
}
}At-Least-Once Publishing
If the relay crashes after sending but before marking published, the event is sent again. Consumers must therefore be idempotent, often using the event id as a dedup key.
Change Data Capture Alternative
Instead of polling, tools like Debezium tail the database transaction log and stream outbox inserts to Kafka automatically — lower latency and no polling load.
Cleaning Up the Outbox
Periodically delete or archive published rows to keep the table small and queries fast.
DELETE FROM outbox WHERE published = true AND created_at < now() - INTERVAL '7 days';When to Use It
Use the outbox when you must keep a database state change and an event publication consistent. It is simpler and more portable than spanning a Kafka transaction across an external database.
Putting It Together
The outbox pattern turns two unreliable writes into one atomic database commit plus a reliable relay. Combine it with idempotent consumers for end-to-end consistency.
Quick Check
Test your understanding of the outbox pattern.
Recap
You learned the transactional outbox pattern.
- Avoids dual-write inconsistency by using one DB transaction.
- An outbox table stores pending events.
- A relay (polling or CDC) publishes to Kafka.
- Consumers must be idempotent due to at-least-once delivery.
Часто задаваемые вопросы
Урок «Шаблон транзакционного исходящего журнала» бесплатный?
Да — полный текст урока «Шаблон транзакционного исходящего журнала» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Advanced Spring Boot 4: Event-Driven Architecture (Kafka), подпишись на CoddyKit PRO. Курс Advanced Spring Boot 4: Event-Driven Architecture (Kafka) содержит 4 уроков всего.
Чему я научусь в уроке «Шаблон транзакционного исходящего журнала»?
Узнайте, как шаблон транзакционного исходящего журнала надёжно связывает транзакцию базы данных с публикацией в Kafka, устраняя несогласованность двойной записи в Spring Boot. Ты практикуешь Advanced Spring Boot 4: Event-Driven Architecture (Kafka) с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Advanced Spring Boot 4: Event-Driven Architecture (Kafka)?
Предыдущий опыт не требуется. Advanced Spring Boot 4: Event-Driven Architecture (Kafka) на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Шаблон транзакционного исходящего журнала»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Advanced Spring Boot 4: Event-Driven Architecture (Kafka)?
Да. Каждый урок Advanced Spring Boot 4: Event-Driven Architecture (Kafka) включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Транзакции Kafka
- Реализация транзакционных производителей
- Семантика обработки «ровно один раз»
- Шаблон транзакционного исходящего журнала