【kafka专栏】Spring kafka消息发送事务处理

在《幂等与事务处理的》的文章中,我们已经为大家介绍使用apache kafka原生API 如何保证:数据被发送Exactly One,发送一次并且只发送一次,不重发不漏发。幂等性的设置仍然很简单,只需要将生产者客户端参数enable.idempotence设置为true即可。

spring:
	kafka:
		producer:
			properties:
			    enable.idempotence: true

本文主要为大家介绍下在SpringBoot环境下结合Spring kafka如何实现幂等性和事务的处理。

一、模拟异常场景

我们看下面的一段代码,使用kafkaTemplate.send向kafka发送数据,但是发送数据之后方法内部抛出了异常。假如我们的代码含义是下面的这样的

  • 用户订单支付,向kafka发送数据,为用户增加积分
  • 然后把用户的订单支付结果存入数据库

订单支付未成功,可能用户余额不足,抛出异常。但是向kafka发送的数据已经发出去了,这显然不是我们希望看到的。我们期望的结果是:订单支付成功和用户积分增加成功,要么都成功,要么都失败。

@Service
public class ProduceService {
    
    
    @Resource
    KafkaTemplate<String, User> kafkaTemplate;

    //异常发生,数据已经发布到kafka,没有事务处理
    public void errorSend(){
    
    
        User user = new User();
        user.setAge(21);
        user.setFirstName("stephen");
        user.setLastName("curry");
        //将user发往zimug-test这个topic
        kafkaTemplate.send("zimug-test",user);
        //模拟后续业务处理发生了异常
        throw new RuntimeException("fail");
    }
}

二、Spring kafka生产者发送消息事务处理

下面是带事务处理的kafka生产者代码,结合Spring kafka的kafkaTemplate使用,代码如下

    //带事务处理的发送方式
    public void rightSend(){
    
    
        User user = new User();
        user.setAge(21);
        user.setFirstName("stephen");
        user.setLastName("curry");
        // 声明事务:operations函数报错,消息就不会发出去。
        kafkaTemplate.executeInTransaction(operations -> {
    
    
            //数据发往kafka
            operations.send("zimug-test",user);
             //模拟后续业务处理发生了异常
            throw new RuntimeException("fail");
        });
    }

上文中的消息不会发生成功,因为我们人工模拟了一个RuntimeException。当operations lambda函数出现异常,发送行为就会回滚,消息发送失败。具体原理可以参考本专栏之前的文章《消息幂等性与事务处理》

三、@Transactional

另外Spring还提供了使用@Transactional注解的方式管理事务,但是需要针对kafka做额外的配置管理,笔者不建议使用这种方式,因为@Transactional注解通常被用于管理数据库事务,如果和kafka的事务混用,如果再结合数据库多数据源、分布式事务相关的处理,很有可能会造成不可预知的问题。所以我建议@Transactional只是管理数据库事务,所以这种方式我就不介绍了,大家知道有这么一种方法就行。面试可以吹吹牛,真实场景就用上面为大家介绍的Spring Kafka 生产者事务管理API即可。

猜你喜欢

转载自blog.csdn.net/hanxiaotongtong/article/details/125698062