「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战」。
6.3.2.5 代码消费并生产数据
实现步骤:
1. 调用之前实现的方法,创建消费者、生产者对象
2. 生产者调用initTransactions初始化事务
3. 编写一个while死循环,在while循环中不断拉取数据,进行处理后,再写入到指定的topic
-
(1) 生产者开启事务
-
(2) 消费者拉取消息
-
(3) 遍历拉取到的消息,并进行预处理(将1转换为男,0转换为女)
-
(4) 生产消息到dwd_user topic中
-
(5) 提交偏移量到事务中
-
(6) 提交事务
-
(7) 捕获异常,如果出现异常,则取消事务
public static void main(String[] args) {
Consumer<String, String> consumer = createConsumer();
Producer<String, String> producer = createProducer();
// 初始化事务
producer.initTransactions();
while(true) {
try {
// 1. 开启事务
producer.beginTransaction();
// 2. 定义Map结构,用于保存分区对应的offset
Map<TopicPartition, OffsetAndMetadata> offsetCommits = new HashMap<>();
// 2. 拉取消息
ConsumerRecords<String, String> records = consumer.poll(Duration.ofSeconds(2));
for (ConsumerRecord<String, String> record : records) {
// 3. 保存偏移量
offsetCommits.put(new TopicPartition(record.topic(), record.partition()),
new OffsetAndMetadata(record.offset() + 1));
// 4. 进行转换处理
String[] fields = record.value().split(",");
fields[1] = fields[1].equalsIgnoreCase("1") ? "男":"女";
String message = fields[0] + "," + fields[1] + "," + fields[2];
// 5. 生产消息到dwd_user
producer.send(new ProducerRecord<>("dwd_user", message));
}
// 6. 提交偏移量到事务
producer.sendOffsetsToTransaction(offsetCommits, "ods_user");
// 7. 提交事务
producer.commitTransaction();
} catch (Exception e) {
// 8. 放弃事务
producer.abortTransaction();
}
}
}
6.3.2.6 测试
往之前启动的console-producer中写入消息进行测试,同时检查console-consumer是否能够接收到消息。
逐个测试一下消息:
-
张三,1,1980-10-09
-
李四,0,1985-11-01
6.3.2.7 模拟异常测试事务
// 3. 保存偏移量
offsetCommits.put(new TopicPartition(record.topic(), record.partition()),
new OffsetAndMetadata(record.offset() + 1));
// 4. 进行转换处理
String[] fields = record.value().split(",");
fields[1] = fields[1].equalsIgnoreCase("1") ? "男":"女";
String message = fields[0] + "," + fields[1] + "," + fields[2];
// 模拟异常
int i = 1/0;
// 5. 生产消息到dwd_user
producer.send(new ProducerRecord<>("dwd_user", message));
启动程序一次,抛出异常。
再启动程序一次,还是抛出异常。
直到我们处理该异常为止。
我们发现,可以消费到消息,但如果中间出现异常的话,offset是不会被提交的,除非消费、生产消息都成功,才会提交事务。