Advanced Spring Boot 4: Event-Driven Architecture (Kafka) · レッスン

トランザクション対応プロデューサーの実装

Spring Bootでトランザクション対応プロデューサーを設定・利用し、メッセージのバッチをすべて正常に送信するか、ひとつも送信しないことを保証します。

レッスン 2/411 ステップ

「トランザクション対応プロデューサーの実装」はCoddyKit上の無料Advanced Spring Boot 4: Event-Driven Architecture (Kafka)レッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAdvanced Spring Boot 4: Event-Driven Architecture (Kafka)学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Advanced Spring Boot 4: Event-Driven Architecture (Kafka)コースには全4レッスンが含まれています。

このレッスンの一部はまだ翻訳されておらず、英語で表示されています。

Atomic Operations with Kafka

In distributed systems, ensuring that a series of operations either all succeed or all fail (atomicity) is crucial. This is where transactional producers in Kafka come in.

They allow you to send multiple messages to different topics and partitions as a single atomic unit. If any part of the transaction fails, all messages sent within that transaction are rolled back.

Identifying Your Transaction

To use transactional producers, you must configure a unique transactional.id for your producer. This ID is essential for Kafka to guarantee exactly-once semantics and recover transactions across producer restarts.

Think of it as a unique name for your producer's transactional session. Kafka uses it to identify the producer and its ongoing transactions.

Spring Boot Configuration

First, ensure you have the spring-kafka dependency. Then, configure your Kafka broker address and the transactional-id-prefix in application.yml. This prefix will be used to generate unique IDs for each producer instance.

# application.yml
spring:
  kafka:
    bootstrap-servers: localhost:9092
    producer:
      # A unique ID prefix for the transactional producer
      transactional-id-prefix: my-app-tx-

Configuring Transactional Producer

Spring Kafka simplifies transactional producer setup. You need to configure your ProducerFactory to be transactional and then create a KafkaTemplate using it.

Notice acks: all is crucial for transactions, ensuring all in-sync replicas acknowledge the message before it's considered committed.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.core.ProducerFactory;
import java.util.HashMap;
import java.util.Map;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.springframework.beans.factory.annotation.Value;

@Configuration
public class KafkaProducerConfig {

    @Value("${spring.kafka.bootstrap-servers}")
    private String bootstrapServers;

    @Value("${spring.kafka.producer.transactional-id-prefix}")
    private String transactionalIdPrefix;

    @Bean
    public ProducerFactory<String, String> producerFactory() {
        Map<String, Object> configProps = new HashMap<>();
        configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
        configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.StringSerializer.class);
        configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.StringSerializer.class);
        configProps.put(ProducerConfig.ACKS_CONFIG, "all"); // Essential for transactions
        configProps.put(ProducerConfig.RETRIES_CONFIG, 0); // Kafka handles retries internally for transactions

        DefaultKafkaProducerFactory<String, String> factory = new DefaultKafkaProducerFactory<>(configProps);
        factory.setTransactionIdPrefix(transactionalIdPrefix); // Set the transactional ID prefix
        return factory;
    }

    @Bean
    public KafkaTemplate<String, String> kafkaTemplate() {
        return new KafkaTemplate<>(producerFactory());
    }
}

Integrating with Spring Transactions

To integrate Kafka transactions with Spring's declarative transaction management (@Transactional), you need to define a KafkaTransactionManager bean.

This manager coordinates the Kafka producer transactions with other Spring-managed transactions (e.g., database operations), allowing you to achieve atomicity across different resource types.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.transaction.KafkaTransactionManager;
import org.springframework.kafka.core.ProducerFactory;

@Configuration
public class KafkaTransactionManagerConfig {

    @Bean
    public KafkaTransactionManager kafkaTransactionManager(ProducerFactory<String, String> producerFactory) {
        return new KafkaTransactionManager(producerFactory);
    }
}

Sending a Single Transactional Message

Now you can use @Transactional on a service method. Any Kafka messages sent within this method using the configured KafkaTemplate will be part of a single transaction.

If the method completes successfully, the transaction is committed. If an exception occurs, it's rolled back and no messages are sent.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@Service
public class TransactionalProducerService {

    private final KafkaTemplate<String, String> kafkaTemplate;

    @Autowired
    public TransactionalProducerService(KafkaTemplate<String, String> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    @Transactional
    public void sendGreeting(String user) {
        String message = "Hello, " + user + "!";
        kafkaTemplate.send("greetings-topic", user, message);
        System.out.println("Attempted to send: " + message);
    }

    // Main method for a runnable Spring Boot application
    @SpringBootApplication
    public static class DemoApplication {
        public static void main(String[] args) {
            // This would typically be run as a Spring Boot application
            // and the service called via a controller or runner.
            // For demonstration, we just show the structure.
            System.out.println("Run this as a Spring Boot app to use the service.");
            // SpringApplication.run(DemoApplication.class, args);
        }
    }
}

Multiple Messages, One Transaction

The real power of transactional producers shines when sending multiple messages. All messages within the @Transactional method are grouped.

If one send fails, all previously sent messages within that transaction are aborted. This ensures data consistency across different topics or partitions.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class OrderProcessingService {

    private final KafkaTemplate<String, String> kafkaTemplate;

    @Autowired
    public OrderProcessingService(KafkaTemplate<String, String> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    @Transactional
    public void processOrder(String orderId, String item) {
        // Send order creation event
        kafkaTemplate.send("order-created-topic", orderId, "Order " + orderId + " created for " + item);
        System.out.println("Sent order creation for: " + orderId);

        // Simulate a failure for demonstration
        if (orderId.equals("FAIL_ORDER")) {
            throw new RuntimeException("Simulated order processing failure!");
        }

        // Send inventory update event
        kafkaTemplate.send("inventory-update-topic", item, "Item " + item + " quantity reduced for order " + orderId);
        System.out.println("Sent inventory update for: " + item);

        System.out.println("Order " + orderId + " processed transactionally.");
    }

    // Main method for a runnable Spring Boot application
    public static void main(String[] args) {
        // This would typically be run as a Spring Boot application
        // and the service called via a controller or runner.
        System.out.println("Run this as a Spring Boot app to use the service.");
    }
}

Transaction Rollback Behavior

If an exception is thrown within a @Transactional method, the KafkaTransactionManager will initiate a transaction rollback.

This means any messages sent to Kafka within that transaction will not be visible to consumers. Kafka's transactional capabilities ensure that partial data is never committed, maintaining data integrity.

Why Atomicity Matters

Transactional producers are crucial for maintaining data integrity in complex event-driven workflows. They prevent scenarios where, for example, an order creation event is sent but the corresponding inventory update fails.

This guarantees that your system's state remains consistent, even in the face of transient errors or application crashes during processing.

Transactional Producer Check

Consider a Spring Boot application sending messages to Kafka using KafkaTemplate within a @Transactional method.

If an unchecked exception occurs after sending the first of two messages, what happens?

Recap: Atomic Messaging

We've learned how to implement transactional producers in Spring Boot Kafka. This involves configuring a transactional.id, enabling transactions in ProducerFactory, using KafkaTransactionManager, and marking service methods with @Transactional.

Transactional producers ensure atomicity, meaning a batch of messages either all commit or all roll back, vital for data consistency. Next, we'll explore achieving exactly-once processing semantics by combining transactional producers with idempotent consumers.

無料で開始

AI チューターと学ぶ Advanced Spring Boot 4: Event-Driven Architecture (Kafka) — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
12
レッスン
48

よくある質問

「トランザクション対応プロデューサーの実装」レッスンは無料ですか?

はい。「トランザクション対応プロデューサーの実装」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Advanced Spring Boot 4: Event-Driven Architecture (Kafka)コースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Advanced Spring Boot 4: Event-Driven Architecture (Kafka)コースには全4レッスンが含まれています。

「トランザクション対応プロデューサーの実装」で何を学びますか?

Spring Bootでトランザクション対応プロデューサーを設定・利用し、メッセージのバッチをすべて正常に送信するか、ひとつも送信しないことを保証します。 ブラウザで直接実行するハンズオンコードでAdvanced Spring Boot 4: Event-Driven Architecture (Kafka)を演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Advanced Spring Boot 4: Event-Driven Architecture (Kafka)を始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのAdvanced Spring Boot 4: Event-Driven Architecture (Kafka)は初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「トランザクション対応プロデューサーの実装」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このAdvanced Spring Boot 4: Event-Driven Architecture (Kafka)レッスンでコードを書いて実行できますか?

はい。すべてのAdvanced Spring Boot 4: Event-Driven Architecture (Kafka)レッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Kafkaトランザクションを理解する
  2. トランザクション対応プロデューサーの実装
  3. Exactly-Once処理セマンティクス
  4. トランザクショナルアウトボックスパターン
← Advanced Spring Boot 4: Event-Driven Architecture (Kafka)に戻る