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

相关推荐
惊讶的猫10 小时前
AMQP 与 RabbitMQ 四大模型
分布式·rabbitmq
灰子学技术11 小时前
istio从0到1:如何解决分布式配置同步问题
分布式·云原生·istio
小马爱打代码11 小时前
ZooKeeper:入门实战
分布式·zookeeper·云原生
永远都不秃头的程序员(互关)12 小时前
CANN赋能AIGC分布式训练:硬核通信,加速大模型智能生成新纪元
分布式·aigc
杜子不疼.13 小时前
CANN集合通信库HCCL的大规模分布式训练通信优化与拓扑感知实践
分布式
ALex_zry1 天前
Redis Cluster 分布式缓存架构设计与实践
redis·分布式·缓存
为什么不问问神奇的海螺呢丶1 天前
n9e categraf rabbitmq监控配置
分布式·rabbitmq·ruby
TTBIGDATA1 天前
【Atlas】Atlas Hook 消费 Kafka 报错:GroupAuthorizationException
hadoop·分布式·kafka·ambari·hdp·linq·ranger
m0_687399841 天前
telnet localhost 15672 RabbitMQ “Connection refused“ 错误表示目标主机拒绝了连接请求。
分布式·rabbitmq
indexsunny1 天前
互联网大厂Java面试实战:微服务与Spring生态技术解析
java·spring boot·redis·kafka·mybatis·hibernate·microservices