在《幂等与事务处理的》的文章中,我们已经为大家介绍使用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即可。