springboot使用kafka事务的示例代码

 更新时间:2024年06月14日 09:38:31   作者:​​​​​​​ 五敷有你  
Kafka 同数据库一样支持事务,当发生异常的时候可以进行回滚,确保消息监听器不会接收到一些错误的或者不需要的消息,本文就来介绍一下springboot使用kafka事务的示例代码,具有一定的参考价值,感兴趣的可以了解一下

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

@GetMapping("/send")
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事务的文章就介绍到这了,更多相关springboot kafka事务内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Jenkins一键打包部署SpringBoot应用的方法步骤

    Jenkins一键打包部署SpringBoot应用的方法步骤

    本文主要介绍了使用Jenkins一键打包部署SpringBoot应用的方法步骤,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • 详解Java如何关闭线程以及线程池

    详解Java如何关闭线程以及线程池

    java如何正确关闭线程以及线程池是一个高频的面试题,本文将为大家详细介绍实现的方法与代码,感兴趣的小伙伴快跟随小编一起学习一下
    2022-04-04
  • @SpringBootApplication注解的使用

    @SpringBootApplication注解的使用

    这篇文章主要介绍了@SpringBootApplication注解的使用,帮助大家更好的理解和学习使用springboot框架,感兴趣的朋友可以了解下
    2021-04-04
  • 快速排序算法原理及java递归实现

    快速排序算法原理及java递归实现

    快速排序 对冒泡排序的一种改进,若初始记录序列按关键字有序或基本有序,蜕化为冒泡排序。使用的是递归原理,在所有同数量级O(n longn) 的排序方法中,其平均性能最好。就平均时间而言,是目前被认为最好的一种内部排序方法
    2014-01-01
  • Java 如何在switch case语句中声明变量

    Java 如何在switch case语句中声明变量

    这篇文章主要介绍了Java 如何在switch case语句中声明变量,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • 浅谈java安全编码指南之堆污染

    浅谈java安全编码指南之堆污染

    什么是堆污染呢?是指当参数化类型变量引用的对象不是该参数化类型的对象时而发生的。我们知道在JDK5中,引入了泛型的概念,在创建集合类的时候,指定该集合类中应该存储的对象类型。如果在指定类型的集合中,引用了不同的类型,那么这种情况就叫做堆污染。
    2021-06-06
  • 将Java对象序列化成JSON和XML格式的实例

    将Java对象序列化成JSON和XML格式的实例

    下面小编就为大家分享一篇将Java对象序列化成JSON和XML格式的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-12-12
  • Java超详细精讲数据结构之bfs与双端队列

    Java超详细精讲数据结构之bfs与双端队列

    广搜BFS的基本思想是: 首先访问初始点v并将其标志为已经访问。接着通过邻接关系将邻接点入队。然后每访问过一个顶点则出队。按照顺序,访问每一个顶点的所有未被访问过的顶点直到所有的顶点均被访问过。广度优先遍历类似与层次遍历
    2022-07-07
  • Java在Linux下 不能处理图形的解决办法 分享

    Java在Linux下 不能处理图形的解决办法 分享

    Java在Linux下 不能处理图形的解决办法 分享,需要的朋友可以参考一下
    2013-06-06
  • Spring事务原理解析

    Spring事务原理解析

    Spring事务有可能会提交,回滚、挂起、恢复,所以Spring事务提供了一种机制,可以让程序员来监听当前Spring事务所处于的状态,这篇文章主要介绍了Spring底层事务原理,需要的朋友可以参考下
    2022-12-12

最新评论