kafka教程-事务:springboot发送消息(大数据)

介绍

kafka中的事务,相当于 关系型数据库(mysql、oracle)中的事务管理

当发送消息 有事务要求时,比如:假设第一条消息发送后,在发第二条消息前出现了异常,那么第一条已经发送的消息也会回滚。当所有消息发送成功才算成功

默认情况下,Spring-kafka自动生成的 KafkaTemplate 实例,没有事务管理,需要修改配置文件激活

注意: 事务激活后,所有的消息发送 只能在事务管理的方法内执行,否则会抛没有事务管理的异常,如下:

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

本文代码

需要先实现 kafka教程-springboot实现简单生产者 文中的代码

本文代码在文中的 生产者工程 做修改

配置文件

下面配置文件中有2处重要:

  • spring.kafka.producer.acks=-1 开启事务,此处必须是-1,否则报错

  • spring.kafka.producer.transaction-id-prefix=kafka_tx. 事务支持

完整配置如下:

server.port=8081

###########【Kafka集群】###########
spring.kafka.bootstrap-servers=hadoop1:9092,hadoop2:9092,hadoop3:9092
###########【初始化生产者配置】###########
# 重试次数
spring.kafka.producer.retries=3
# 应答级别:多少个分区副本备份完成时向生产者发送ack确认(可选0、1、all/-1)
#spring.kafka.producer.acks=1
spring.kafka.producer.acks=-1 ################### 开启事务,此处必须是-1########################
# 批量大小
spring.kafka.producer.batch-size=16384
# 提交延时
spring.kafka.producer.properties.linger.ms=0
# 当生产端积累的消息达到batch-size或接收到消息linger.ms后,生产者就会将消息提交给kafka
# linger.ms为0表示每接收到一条消息就提交给kafka,这时候batch-size其实就没用了

# 生产端缓冲区大小
spring.kafka.producer.buffer-memory = 33554432
# Kafka提供的序列化和反序列化类
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer


spring.kafka.producer.transaction-id-prefix=kafka_tx.

方式一:注解方式

@GetMapping("/kafka3/{msg}")
@Transactional(rollbackFor = Exception.class)
public String sendMessage3(@PathVariable("msg") String msg){
    //事务的支持
    kafkaTemplate.send("userlog",msg);
    //当msg是是error时,故意报错,演示事务回滚是否生效
    if("error".equals(msg)){
        int i=1/0;
    }
    kafkaTemplate.send("userlog",msg+"--2");
    return "消息已发送";
}

测试

访问下面链接测试:

当发送消息是 error 时,将会执行抛错代码,虽然已经发了一个消息,但是后面报错,由于有事务管理,之前的消息也不会发出

方式二:代码方式

通过 executeInTransaction() 方法实现

@GetMapping("/kafka4/{message}")
public String sendMessage4(@PathVariable("message") final String msg) {
    // 声明事务:后面报错消息不会发出去
    kafkaTemplate.executeInTransaction(new KafkaOperations.OperationsCallback(){
        @Override
        public Object doInOperations(KafkaOperations operations) {

            operations.send("userlog", msg);
            if("error".equals(msg)){
                 int i=1/0;
            }
            operations.send("userlog",msg+"--2");
            return null;
         }
     });
     return "消息已发送";
}

注意:启用事务后,必须通过事务发消息

启用事务后,发送消息 必须有事务管理。如果没有事务,直接发送消息,会报错

代码

/**
 * 启用事务后,如果没有事务,直接发送消息,会报错
 * @param msg
 * @return
 */
@GetMapping("/kafka5/{message}")
public String sendMessage4(@PathVariable("message") String msg) {
    kafkaTemplate.send("userlog", msg);

    return "消息已发送";
}

报错如下:

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

原文出处:/show_1IX3261XO8vX.html