springboot集成整合kafka-kafka事务、生产者事务支持、kafkaTemplate.executeInTransaction

写在前面:各位看到此博客的小伙伴,如有不对的地方请及时通过私信我或者评论此博客的方式指出,以免误人子弟。多谢!

先看下下面这种情况,程序都出错了,按理说消息也不应该成功

    @GetMapping("/send9")
    public void test9(String message) {
        kafkaTemplate.send(topic, message);
        throw new RuntimeException("fail");
    }

但是执行结果是发生了异常并且消息发送成功了:

Kafka 同数据库一样支持事务,当发生异常的时候可以进行回滚,确保消息监听器不会接收到一些错误的或者不需要的消息。kafka事务属性是指一系列的生产者生产消息和消费者提交偏移量的操作在一个事务,或者说是是一个原子操作),同时成功或者失败。使用事务也很简单,需要先开启事务支持,然后再使用。

先看下怎么开启事务,如果使用默认配置只需要在yml添加spring.kafka.producer.transaction-id-prefix配置来开启事务,之前没有使用默认的配置,自定义的kafkaTemplate,那么需要在ProducerFactory中设置事务Id前缀开启事务并将KafkaTransactionManager注入到spring中,看下KafkaProducerConfig完整代码:

@Configuration
@EnableKafka
public class KafkaProducerConfig {

    @Value("${kafka.producer.servers}")
    private String servers;
    @Value("${kafka.producer.retries}")
    private int retries;

    public Map<String,Object> producerConfigs(){
        Map<String,Object> props = new HashMap<>();
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, servers);
        props.put(ProducerConfig.RETRIES_CONFIG,retries);
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        // 配置分区策略
        props.put(ProducerConfig.PARTITIONER_CLASS_CONFIG,"com.example.springbootkafka.config.CustomizePartitioner");
        // 配置生产者拦截器
        props.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG,"com.example.springbootkafka.interceptor.CustomProducerInterceptor");
        // 配置拦截器消息处理类
        SendMessageInterceptorUtil sendMessageInterceptorUtil = new SendMessageInterceptorUtil();
        props.put("interceptorUtil",sendMessageInterceptorUtil);
        return props;
    }

    @Bean
    public ProducerFactory<String,String> producerFactory(){
        DefaultKafkaProducerFactory producerFactory = new DefaultKafkaProducerFactory(producerConfigs());
        //设置事务Id前缀 开启事务
        producerFactory.setTransactionIdPrefix("tx-");
        return producerFactory;
    }

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

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

配置开启事务后,使用大体有两种方式,先记录下第一种使用事务方式:使用 executeInTransaction 方法

直接看下代码:

    @GetMapping("/send11")
    public void test11(String message) {
        kafkaTemplate.executeInTransaction(operations ->{
            operations.send(topic,message);
            throw new RuntimeException("fail");
        });
    }

当然你可以这么写:

    @GetMapping("/send11")
    public void test11(String message) {
        kafkaTemplate.executeInTransaction(new KafkaOperations.OperationsCallback(){
            @Override
            public Object doInOperations(KafkaOperations operations) {
                operations.send(topic,message);
                throw new RuntimeException("fail");
            }
        });
    }

启动项目,访问http://localhost:8080/send10?message=test10 结果如下: 

如上:消费者没打印消息,说明消息没发送成功,并且前面会报错org.apache.kafka.common.KafkaException: Failing batch since transaction was aborted 的错误,说明事务生效了。

第一种使用事务方式:使用 @Transactional 注解方式  直接在方法上加上@Transactional注解即可,看下代码:

    @GetMapping("/send12")
    @Transactional
    public void test12(String message) {
        kafkaTemplate.send(topic, message);
        throw new RuntimeException("fail");
    }

如果开启的事务,则后续发送消息必须使用@Transactional注解或者使用kafkaTemplate.executeInTransaction() ,否则抛出异常,异常信息如下:

贴下完整的异常吧:java.lang.IllegalStateException: No transaction is in process; possible solutions: run the template operation within the scope of a template.executeInTransaction() operation, start a transaction with @Transactional before invoking the template method, run in a transaction started by a listener container when consuming a record

要在springboot集成kafka生产者,需要遵循以下步骤: 1. 添加Maven依赖 在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> <version>2.7.2</version> </dependency> ``` 2. 配置Kafka生产者 在application.properties文件中添加Kafka的配置: ```properties spring.kafka.producer.bootstrap-servers=<broker地址> spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer ``` 3. 创建Kafka生产者 在代码中创建Kafka生产者: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.stereotype.Service; @Service public class KafkaProducerService { private final KafkaTemplate<String, String> kafkaTemplate; @Autowired public KafkaProducerService(KafkaTemplate<String, String> kafkaTemplate) { this.kafkaTemplate = kafkaTemplate; } public void sendMessage(String topic, String message) { this.kafkaTemplate.send(topic, message); } } ``` 4. 发送消息 在需要发送消息的地方,注入KafkaProducerService,并调用sendMessage方法: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController public class MessageController { private final KafkaProducerService kafkaProducerService; @Autowired public MessageController(KafkaProducerService kafkaProducerService) { this.kafkaProducerService = kafkaProducerService; } @PostMapping("/message") public void sendMessage(@RequestBody String message) { this.kafkaProducerService.sendMessage("test-topic", message); } } ``` 以上就是在springboot集成Kafka生产者的步骤。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值