Seata事务集成Kafka,实现事务一致性

将kafka消息暂存至ThreadLocal中,seata事务完成后,再发送消息至kafka,如果seata事务失败,不发送消息。

一、 写一个注解拦截类

java 复制代码
@Aspect
@Component
@Slf4j
public class BusinessLogTestAspect {
    @Around("@annotation(com.cloud.util.businesslog.BusinessLogKevin)")
    public Object toLog(ProceedingJoinPoint joinPoint) throws Throwable {
        GlobalTransaction globalTransaction = GlobalTransactionContext.getCurrentOrCreate();
        globalTransaction.begin();
        Object result = null;
        try{
            result = joinPoint.proceed();
            globalTransaction.commit();
            // 发送kafka信息
            List<String> messageList = KafkaThreadLocal.kafkaThreadLocal.get();
            KafkaThreadLocal.kafkaThreadLocal.remove();
            if(ObjectUtil.isNotEmpty(messageList)) {
                //  发送Kafka消息
                KafkaProducer<String, String> producer = null;
                try {
                    producer = createKafkaProducer();
                    for(String message : messageList) {
                         producer.send(new ProducerRecord<>("ustomer", message));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if(producer != null) {
                        producer.close();
                    }
                }
            }

        } catch (Exception e) {
            KafkaThreadLocal.kafkaThreadLocal.remove();
            globalTransaction.rollback();
        }
        System.out.println("localStatus3 role:" + globalTransaction.getGlobalTransactionRole());
        return result;
    }

二、写一个创建kafka生产端的对象

java 复制代码
       private KafkaProducer<String, String> createKafkaProducer() {
        Properties props = new Properties();
        props.put(BOOTSTRAP_SERVERS_CONFIG, "17.30.194.2:9092,172.0.14.28:9093,17.30.19.9:9092");
//        props.put(ENABLE_IDEMPOTENCE_CONFIG, "true");
//        props.put(TRANSACTIONAL_ID_CONFIG, String.valueOf(System.currentTimeMillis()));
        props.put(KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
        props.put(VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
        props.put("security.protocol", "SASL_PLAINTEXT");
        props.put("sasl.mechanism", "SCRAM-SHA-256");
        props.put("sasl.jaas.config", "org.apache.kafka.common.security.scram.ScramLoginModule required username='username' password='userpassword';");

        return new KafkaProducer<>(props);
    }

三、将消息暂存至ThreadLocal

java 复制代码
   public class KafkaThreadLocal {
    public static final ThreadLocal<List<String>> kafkaThreadLocal = new ThreadLocal<>();

    public static void send(String message) {
        List<String> messageList = kafkaThreadLocal.get();
        if(ObjectUtil.isEmpty(messageList)) {
            messageList = Lists.newArrayList();
        }
        messageList.add(message);
        kafkaThreadLocal.set(messageList);
    }
}

另外一种办法比较简单:

io.seata.tm.api.transaction.TransactionHook 实现这个接口

io.seata.tm.api.transaction.TransactionHookManager 注册Hook

相关推荐
Thomas21431 天前
spark view永久保存 + paimon对应的view
大数据·分布式·spark
_codemonster1 天前
分布式深度学习训练框架Horovod
人工智能·分布式·深度学习
❀͜͡傀儡师1 天前
全新分布式ID组件TSID支持N种数据类型
分布式
乌恩大侠1 天前
【AI-RAN 调研】软银株式会社的 “AITRAS” 基于 Arm 架构的 NVIDIA 平台 实现 集中式与分布式 AI-RAN 架构
人工智能·分布式·fpga开发·架构·usrp·mimo
alonewolf_991 天前
ZooKeeper ZAB协议源码深度剖析:从理论到实践的分布式一致性指南
分布式·zookeeper
indexsunny1 天前
互联网大厂Java求职面试实战:Spring Boot微服务与Kafka消息队列解析
java·spring boot·微服务·面试·kafka·jpa
机灵猫2 天前
Redisson 到底能做什么?从分布式锁说起
分布式
U-Mail邮件系统2 天前
U-Mail企业邮件系统分布式部署方案
分布式
鱼跃鹰飞2 天前
面试题:Kafka的零拷贝的底层实现是什么?是MMAP还是sendFile还是其他的?
分布式·kafka·系统架构
工业甲酰苯胺2 天前
【面试题】RabbitMQ 中无法路由的消息会去到哪里?
分布式·rabbitmq