如何用 RabbitMQ 解决分布式事务?

通过RabbitMQ实现分布式事务 通过RabitMQ实现分布式事务题前言业务需求核心原理核心难点解决问题思路代码实现其他总结 前言 这篇文章是通过学习哔哩哔哩中的视频“阿里架构师如何30分钟基于MQ解决分布式事务问题”,原视频连接https://www.bilibili.com/video/BV15p4y1D7d7?p=2 业务需求 这是一次简单的模拟分布式事务的:假设我们现在需要支付宝向余额宝转账100元。支付宝(系统A)向余额宝(系统B)转账100元,支付宝余额-100,余额宝余额加100。这涉及到两个系统,需要用到分布式事务。 核心原 阅读详情

要说哪种分布式事务处理方案效率高,必然绕不开消息中间件!基于消息中间件的两阶段提交方案,通常用在高并发场景下。这种方式通过牺牲数据的强一致性换取性能的大幅提升,不过实现这种方式的成本和复杂度是比较高的,使用时还要看实际业务情况。

1. 思路分析

先来说说整体思路。

有一个名词叫做消息驱动的微服务,相信很多小伙伴都听说过。怎么理解呢?

在微服务系统中,服务之间的互相调用,我们可以使用 HTTP 的方式,例如 OpenFeign,也可以使用 RPC 的方式,例如 Dubbo,除了这些方案之外,我们也可以使用消息驱动,这是一种典型的响应式系统设计方案。

在消息驱动的微服务中,服务之间不再互相直接调用,当服务之间需要通信时,就把通信内容发送到消息中间件上,另一个服务则通过监听消息中间件中的消息队列,来完成相应的业务逻辑调用,过程就是这么个过程,并不难,具体怎么玩,我们继续往下看。

2. 业务分析

折腾了半天,后来松哥在网上找到了一个别人写好的例子,我觉得用来演示这个问题特别合适,所以我就没有自己写案例了,直接用别人的代码,我们来逐个分析,跟前面讲分布式事务 Seata 的方式一致。

首先我们来看如下一张流程图,这是一个用户购票的案例:

当用户想要购买一张票时:

  • 向新订单队列中写入一条数据。
  • Order Service 负责消费这个队列中的消息,完成订单的创建,然后再向新订单缴费队列中写入一条消息。
  • User Service 负责消费新订单缴费队列中的消息,在 User Service 中完成对用户账户余额的划扣,然后向新订单转移票队列中写入一条消息。
  • Ticket Service 负责消费新订单转移票队列,在 Ticket Service 中完成票的转移,然后发送一条消息给订单完成队列。
  • 最后 Order Service 中负责监听订单完成队列,处理完成后的订单。

这就是一个典型的消息驱动微服务,也是一个典型的响应式系统。在这个系统中,一共有三个服务,分别是:

  • Order Service
  • User Service
  • Ticket Service

这三个服务之间不会进行任何形式的直接调用,大家有事都是直接发送到消息中间件,其他服务则从消息中间件中获取自己想要的消息然后进行处理。

具体到我们的实践中,则多了一个检查票是否够用的流程,如下图:

创建订单时,先由 Ticket 服务检查票是否够用,没问题的话再继续发起订单的创建。其他过程我就不说了。

另外还需要注意,在售票系统中,由于每张票都不同,例如每张票可能有座位啥的,因此一张票在数据库中往往是被设计成一条记录。

3. 实践

流程我已经说明白了,接下来我们就来看看具体的代码实践。

3.1 准备数据库

首先我们准备三个数据库,分别是:

javaboy_order:订单库,用户创建订单等操作,在这个数据库中完成。

javaboy_ticket:票务库,这个库中保存着所有的票据信息,每一张票都是一条记录,都保存在这个库中。

javaboy_user:用户库,这里保存着用户的账户余额以及付款记录等信息。

每个库中都有各自对应的表,为了操作方便,这些表不用自己创建,将来等项目启动了,利用 JPA 自动创建即可。

3.2 项目概览

我们先来整体上看下这个项目,公众号后台回复 mq_tran 可以下载完整代码:

一共有五个服务:

  • eureka:注册中心
  • order:订单服务
  • service:公共模块
  • ticket:票务服务
  • user:用户服务
  • 下面分别来说。

3.3 注册中心

有人说,都消息驱动了,还要注册中心干嘛?

消息驱动没错,消息驱动微服务之后每个服务只管把消息往消息中间件上扔,每个服务又只管消费消息中间件上的消息,这个时候对于服务注册中心似乎不是那么强需要。不过在我们这个案例中,消息驱动主要用来处理事务问题,其他常规需求我们还是用 OpenFeign 来处理,所以这里我们依然需要一个注册中心。

这里的注册中心我就选择常见的 Eureka,省事一些。由于本文主要是和大家聊分布式事务,所以涉及到微服务的东西我就简单介绍下,不会占用过多篇幅,如果大家还不熟悉 Spring Cloud 的用法,可以在公众号后台回复 vhr 有一套视频介绍。

服务注册中心的创建记得加上 Spring Security,将自己的服务注册中心保护起来。

这块有一个小小的细节和大家多说两句。

Eureka 用 Spring Security 保护起来之后,以后其他服务注册都是通过 Http Basic 来认证,所以我们要在代码中开启 Http Basic 认证,如下(以前旧版本不需要下面这段代码,但是新版本需要):

3.4 购票服务

接下来我们就来看看购票服务。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .httpBasic()
                .and().formLogin().and().csrf().disable();
    }
}

购票是从下订单开始,所以我们就先从订单服务 order 开始整个流程的分析。

3.4.1 新订单处理(order)

当用户发起一个购票请求后,这个请求发送到 order 服务上,order 服务首先会向 order:new 队列发送一条消息,开启一个订单的处理流程。代码如下:

@Transactional
@PostMapping("")
public void create(@RequestBody OrderDTO dto) {
    dto.setUuid(UUID.randomUUID().toString());
    rabbitTemplate.convertAndSend("order:new", dto);
}

上面设置的 UUID 是整个订单在处理过程中的一个唯一标志符,也算是一条主线。

order:new​ 队列中的消息将被 ticket 服务消费,ticket 服务消费 order:new​ 中的消息,并进行锁票操作(锁票的目的防止有两个消费同时购买同一张票),锁票成功后,ticket 服务将向 order:locked​ 队列发送一条消息,表示锁票成功;否则向 order:fail 队列发送一条消息表示锁票失败。

这里的 OrderDTO 对象将贯穿整个购票过程。

3.4.2 锁票(ticket)

锁票操作是在 ticket 服务中完成的,代码如下:

@Transactional
@RabbitListener(queues = "order:new")
public void handleTicketLock(OrderDTO msg) {
    LOG.info("Get new order for ticket lock:{}", msg);
    int lockCount = ticketRepository.lockTicket(msg.getCustomerId(), msg.getTicketNum());
    if (lockCount == 0) {
        msg.setStatus("TICKET_LOCK_FAIL");
        rabbitTemplate.convertAndSend("order:fail", msg);
    } else {
        msg.setStatus("TICKET_LOCKED");
        rabbitTemplate.convertAndSend("order:locked", msg);
    }
}

先调用 lockTicket 方法去数据库中锁票,所谓的锁票就是将要购买的票的 lock_user 字段设置为 customer_id(购买者的 id)。

如果锁票成功(即数据库修改成功),设置 msg 的状态为 TICKET_LOCKED​,同时发送消息到 order:locked 队列,表示锁票成功。

如果锁票失败(即数据库修改失败),设置 msg 的状态为 TICKET_LOCK_FAIL​,同时发送消息到 order:fail 队列,表示锁票失败。

3.4.2 锁票成功(order)

接下来,由 order 服务消费 order:locked 队列中的消息,也就是锁票成功后接下来的操作。

@Transactional
@RabbitListener(queues = "order:locked")
public void handle(OrderDTO msg) {
    LOG.info("Get new order to create:{}", msg);
    if (orderRepository.findOneByUuid(msg.getUuid()) != null) {
        LOG.info("Msg already processed:{}", msg);
    } else {
        Order order = newOrder(msg);
        orderRepository.save(order);
        msg.setId(order.getId());
    }
    msg.setStatus("NEW");
    rabbitTemplate.convertAndSend("order:pay", msg);
}

锁票成功后,先根据订单的 UUID 去订单数据库查询,是否已经有订单记录了,如果有,说明这条消息已经被处理了,可以防止订单的重复处理(这块主要是解决幂等性问题)。

如果订单还没有被处理,则创建一个新的订单对象,并保存到数据库中,创建新订单对象的时候,需要设置订单的 status 为 NEW。

最后设置 msg 的 status 为 NEW,然后向 order:pay​ 队列发送一条消息开启付款流程,付款是由 user 服务提供的。user 服务中会检查用户的账户余额是否够用,如果不够用,就会发送消息到 order:ticket_error​ 队列,表示订票失败;如果余额够用,则进行正常的付款操作,并在付款成功后发送消息到 order:ticket_move 队列,开启票的转移。

3.4.3 缴费(user)

锁票成功后,接下来就是付费了,付费服务由 user 提供。

@Transactional
@RabbitListener(queues = "order:pay")
public void handle(OrderDTO msg) {
    LOG.info("Get new order to pay:{}", msg);
    // 先检查payInfo判断重复消息。
    PayInfo pay = payInfoRepository.findOneByOrderId(msg.getId());
    if (pay != null) {
        LOG.warn("Order already paid, duplicated message.");
        return;
    }
    Customer customer = customerRepository.getById(msg.getCustomerId());
    if (customer.getDeposit() < msg.getAmount()) {
        LOG.info("No enough deposit, need amount:{}", msg.getAmount());
        msg.setStatus("NOT_ENOUGH_DEPOSIT");
        rabbitTemplate.convertAndSend("order:ticket_error", msg);
        return;
    }
    pay = new PayInfo();
    pay.setOrderId(msg.getId());
    pay.setAmount(msg.getAmount());
    pay.setStatus("PAID");
    payInfoRepository.save(pay);
    customerRepository.charge(msg.getCustomerId(), msg.getAmount());
    msg.setStatus("PAID");
    rabbitTemplate.convertAndSend("order:ticket_move", msg);
}

这里的执行步骤如下:

  • 首先根据订单 id 去查找付款信息,检查当前订单是否已经完成付款,如果已经完成服务,则直接 return,这一步也是为了处理幂等性问题。
  • 根据顾客的 id,查找到顾客的完整信息,包括顾客的账户余额。
  • 检查顾客的账户余额是否足够支付票价,如果不够,则设置 msg 的 status 为 NOT_ENOUGH_DEPOSIT,同时向order:ticket_error 队列发送消息,表示订票失败。
  • 如果顾客账户余额足够支付票价,则创建一个 PayInfo 对象,设置相关的支付信息,并存入pay_info 表中。
  • 调用 charge 方法完成顾客账户余额的扣款。
  • 发送消息到order:ticket_move 队列中,开启交票操作。

3.4.4 交票(ticket)

@Transactional
@RabbitListener(queues = "order:ticket_move")
public void handleTicketMove(OrderDTO msg) {
    LOG.info("Get new order for ticket move:{}", msg);
    int moveCount = ticketRepository.moveTicket(msg.getCustomerId(), msg.getTicketNum());
    if (moveCount == 0) {
        LOG.info("Ticket already transferred.");
    }
    msg.setStatus("TICKET_MOVED");
    rabbitTemplate.convertAndSend("order:finish", msg);
}

调用 moveTicket 方法完成交票操作,也就是设置 ticket 表中票的 owner 为 customerId。

交票成功后,发送消息到 order:finish 队列,表示交票完成。

3.4.5 订单完成(order)

@Transactional
@RabbitListener(queues = "order:finish")
public void handleFinish(OrderDTO msg) {
    LOG.info("Get finished order:{}", msg);
    Order order = orderRepository.getById(msg.getId());
    order.setStatus("FINISH");
    orderRepository.save(order);
}

这里的处理就比较简单,订单完成后,就设置订单的状态为 FINISH 即可。

上面介绍的是一条主线,顺利的话,消息顺着这条线走一遍,一个订单就处理完成了。

不顺利的话,就有各种幺蛾子,我们分别来看。

3.4.6 锁票失败(order)

锁票是在 ticket 服务中完成的,如果锁票失败,就会直接向 order:fail 队列发送消息,该队列的消息由 order 服务负责消费。

3.4.7 扣款失败(ticket)

扣款操作是在 user 中完成的,扣款失败就会向 order:ticket_error 队列中发送消息,该队列的消息由 ticket 服务负责消费。

@Transactional
@RabbitListener(queues = "order:ticket_error")
public void handleError(OrderDTO msg) {
    LOG.info("Get order error for ticket unlock:{}", msg);
    int count = ticketRepository.unMoveTicket(msg.getCustomerId(), msg.getTicketNum());
    if (count == 0) {
        LOG.info("Ticket already unlocked:", msg);
    }
    count = ticketRepository.unLockTicket(msg.getCustomerId(), msg.getTicketNum());
    if (count == 0) {
        LOG.info("Ticket already unmoved, or not moved:", msg);
    }
    rabbitTemplate.convertAndSend("order:fail", msg);
}

当扣款失败的时候,做三件事:

  • 撤销票的转移,也就是把票的 owner 字段重新置为 null。
  • 撤销锁票,也就是把票的lock_user 字段重新置为 null。
  • 向order:fail 队列发送订单失败的消息。

3.4.8 下单失败(order)

下单失败的处理在 order 服务中,有三种情况会向 order:fail 队列发送消息:

  • 锁票失败
  • 扣款失败(客户账户余额不足)
  • 订单超时
@Transactional
@RabbitListener(queues = "order:fail")
public void handleFailed(OrderDTO msg) {
    LOG.info("Get failed order:{}", msg);
    Order order;
    if (msg.getId() == null) {
        order = newOrder(msg);
        order.setReason("TICKET_LOCK_FAIL");
    } else {
        order = orderRepository.getById(msg.getId());
        if (msg.getStatus().equals("NOT_ENOUGH_DEPOSIT")) {
            order.setReason("NOT_ENOUGH_DEPOSIT");
        }
    }
    order.setStatus("FAIL");
    orderRepository.save(order);
}

该方法的具体处理逻辑如下:

  • 首先查看是否有订单 id,如果连订单 id 都没有,就说明是锁票失败,给订单设置 reason 属性的值为TICKET_LOCK_FAIL。
  • 如果有订单 id,则根据 id 查询订单信息,并判断订单状态是否为NOT_ENOUGH_DEPOSIT​,这个表示扣款失败,如果订单状态是NOT_ENOUGH_DEPOSIT,则设置失败的 reason 也为此。
  • 最后设置订单状态为 FAIL,然后更新数据库中的订单信息即可。

3.4.9 订单超时(order)

order 服务中还有一个定时任务,定时去数据库中捞取那些处理失败的订单,如下:

@Scheduled(fixedDelay = 10000L)
public void checkInvalidOrder() {
    ZonedDateTime checkTime = ZonedDateTime.now().minusMinutes(1L);
    List<Order> orders = orderRepository.findAllByStatusAndCreatedDateBefore("NEW", checkTime);
    orders.stream().forEach(order -> {
        LOG.error("Order timeout:{}", order);
        OrderDTO dto = new OrderDTO();
        dto.setId(order.getId());
        dto.setTicketNum(order.getTicketNum());
        dto.setUuid(order.getUuid());
        dto.setAmount(order.getAmount());
        dto.setTitle(order.getTitle());
        dto.setCustomerId(order.getCustomerId());
        dto.setStatus("TIMEOUT");
        rabbitTemplate.convertAndSend("order:ticket_error", dto);
    });
}

可以看到,这里是去数据库中捞取那些状态为 NEW 并且是 1 分钟之前的订单,根据前面的分析,当锁票成功后,就会将订单的状态设置为 NEW 并且存入数据库中。换言之,当锁票成功一分钟之后,这张票还没有卖掉,就设置订单超时,同时向 order:ticket_error 队列发送一条消息,这条消息在 ticket 服务中被消费,最终完成撤销交票、撤销锁票等操作。

这就是大致的代码处理流程。

再来回顾一下前面那张图:

结合着代码来看这张图是不是就很容易懂了。

3.5 测试

接下来我们来进行一个简单的测试。

先来一个订票失败的测试,如下:

由于用户只有 1000 块钱,这张票要 10000,所以购票必然失败。请求执行成功后,我们查看 order 表,多了如下一条记录:

可以看到,订单失败的理由就是账户余额不足。此时查看 ticket 和 user 表,发现都完好如初(如果需要,则已经反向补偿了)。

接下来我们手动给 ticket 表中 lock_user 字段设置一个值,如下:

这个表示这张票已经被人锁定了。

然后我们发起一次购票请求(这次可以把金额设置到合理范围,其实不设置也行,反正这次失败还没走到付款这一步):

请求发送成功后,接下来我们去查看 order 表,多了如下一条记录:

可以看到,这次下单失败的理由是锁票失败。此时查看 ticket 和 user 表,发现都完好如初(如果需要,则已经反向补偿了)。

最后再来一次成功测试,先把 ticket 表中的 lock_user 字段置空,然后发送如下请求:

这次购票成功,查看 ticket 表,发票已经票有所属:

查看订单表:

可以多了一条成功的购票记录。

查看用户表:

用户账户已扣款。

查看支付记录表:

可以看到已经有了支付记录。

4. 总结

整体上来说,上面这个案例,技术上并没有什么难的,复杂之处在于设计。一开始要设计好消息的处理流程以及消息处理失败后如何进行补偿,这个是比较考验大家技术的。

另外上面案例中,消息的发送和消费都用到了 RabbitMQ 中的事务机制(确保消息消费成功)以及 Spring 中的事务机制(确保消息发送和数据保存同时成功),这些我就不再赘述了。

总之,通过消息中间件处理分布式事务,这种方式通过牺牲数据的强一致性换取性能的大幅提升,但是实现这种方式的成本和复杂度是比较高的,使用时还要看实际业务情况。

分布式事务解决方案之RabbitMQ 分布式事务问题 以电商业务为例,订单服务对应的订单数据库,库存服务对应的库存数据库,多个数据源之间存在了分布式事务问题。如何保证在订单生成后,正确的扣除库存,或者在订单生成失败时,还原扣除的库存,这就是分布式事务将要解决的问题。 解决分布式事务前的业务逻辑: @Transaction(rollbackFor=Exception.class) publicvoidcreateOrder(OrderInfoorderInfo)throwsException{ //订单... 阅读详情

相关推荐

RabbitMq分布式事务解决方案第一篇

前言 微服务架构下,相比单机事务,一个比较复杂的地方在于,在分布式环境下,面对的是分布式事务,分布式事务整体来说无法严格遵循传统的ACID4个特性,而只能根据系统的业务指标,通常满足可用性,和最终一致性,这也是不少互联网产品的实践结果的选择 在分布式事务一章中,探讨了有关常用分布式事务的几种解决方案,可以依据自己所在项目的特点,有选择的使用,比如对数据的一致性要求严格而对并发数可容忍的,可以考虑使用seata解决,对并发要求高,同时对数据一致性的要求也比较高的,可以考虑使用rocketMq事务消息 下面要介

congge 5万+

RabbitMQ——解决分布式事务问题,RabbitMQ的重要作用之一!!!通过可靠生产和可靠消费来完美解决!

分布式事务是指涉及多个独立的计算机系统(也称为节点或参与者)之间的事务处理。在分布式系统中,每个节点可能各自拥有自己的数据存储和事务管理机制。分布式事务的目标是保证在跨多个节点执行的一系列操作可以以一致和可靠的方式执行和提交,即使在面对故障或并发操作时也能保持数据的完整性和一致性。实现分布式事务可以采用两阶段提交(Two-Phase Commit)协议或三阶段提交(Three-Phase Commit)协议等机制。这些协议通过协调参与者之间的状态和决策来实现分布式事务的一致性。

我热爱学习,也乐于分享。无论是科技前沿的洞见,还是生活中的小技巧,我都会在这里与你分享。我相信,知识就是力量,而分享则能让这份力量得到更好的传递。 2003

rabbitmq分布式事务

基于rabbit和本地消息表实现可靠消息一致性分布式事务,项目下载下来直接可以用了,已经包含了配置文件和数据库脚本,有问题的可以给我私信。项目架构springboot、nacos、rabbitMq、redis、MySQL

实战:RabbitMQ的分布式事务处理

1.背景介绍 分布式事务处理是一种在多个节点之间处理事务的方法,它可以确保在分布式系统中的多个节点之间的事务处理的一致性和完整性。在分布式系统中,事务可能涉及多个节点,这使得事务处理变得复杂。因此,分布式事务处理是一项重要的技术,它可以确保在分布式系统中的事务处理的一致性和完整性。 RabbitMQ是一种开源的消息队列系统,它可以用于分布式系统中的事务处理。在这篇文章中,我们将讨论Rabbit...

AI天才研究院 1834

开源处理器Rocket的分支预测机制研究与性能评估(二)

Rocket是基于RISC-V指令集架构的开源处理器,具有分支预测功能,其实现了GShare分支预测机制,在分析Rocket处理器分支预测处理过程、分支预测实现原理的基础上,利用模拟器进行了性能测试,并依据测试结果,对Rocket处理器分支预测参数配置给出建议。

leishangwen的专栏 5689

用户视角下的vfsglobal预约困境:从注册到登录的全流程避坑指南

本文详细解析了vfsglobal签证预约系统从注册到登录的全流程操作,帮助用户避开常见技术陷阱。针对IP限制、DNS解析、浏览器缓存等登录障碍提供实用解决方案,并揭示账号管理的隐藏规则与支付环节的延时处理技巧,助力用户高效完成签证预约。

ol78901234的博客 870

rabbitmq-04 rabbitmq解决分布式事务

1.RabbitMQ消息重试机制 消费者在消费消息的时候,如果消费者业务逻辑出现程序异常,这时候应该如何处理? 答案:使用消息重试机制。(springboot默认有消息重试机制) 1.1 如何合适选择重试机制 消费者获取到消息后,调用第三方接口,但接口暂时无法访问,是否需要重试? (需要重试机制) 消费者获取到消息后,抛出数据转换异常,是否需要重试?(不需要重试机制)需要发布进行解决。 ...

沐宇熙IT成长之路 1万+

软件缺陷(定义+表现形式+优先级+信息+产生原因),看完这篇文章就懂了

软件缺陷软件缺陷的定义软件缺陷的表现形式软件缺陷产生的原因软件缺陷的根源软件缺陷的费用软件缺陷的信息 软件缺陷的定义 IEEE 1983 of IEEE Stardard 729中软件缺陷做了一个标准的定义: 从产品内部看,软件缺陷是软件产品开发或维护过程中所存在的错误、毛病等各种问题;从外部看,软件缺陷是系统所需要实现的某种功能的失效或违背。 因此软件缺陷就是软件产品中所存在的问题,最终表现为用户所需要的功能没有完全实现,没有满足用户的需求。 缺陷不是bug,缺陷包含bug,缺陷的范围更大。 软件缺陷

qq_40676418的博客 1万+

RabbitMQ解决分布式事务

RabbitMQ解决分布式事务 案例: 经典案例,以目前流行点外卖的案例,用户下单后,调用订单服务,让后订单服务调用派单系统通知送外卖人员送单,这时候订单系统与派单系统采用MQ异步通讯。 RabbitMQ解决分布式事务原理: 采用最终一致性原理。 需要保证以下三要素1、确认生产者一定要将数据投递到MQ服务器中(采用MQ消息确认机制)2、MQ消费者消息能够正确消费消息,采用手动ACK模式,使用不...

art_code的博客 1565

欧姆龙NX控制器与Sysmac studio的电机配置方法

使用歐姆龍NX控制器與Sysmac studio控制電機簡單運動 <上> — 環境配置0. 前言1. 實際硬件連接2. Sysmac studio 配置2.1 新建工程2.2 通信設置2.2.1 軟件內通信設置2.2.2 上位機本地通信設置 0. 前言 筆者最近需要使用到歐姆龍的多軸運動控制器來控制電機運動,但網路上關於Sysmac studio的教程或文章較為零散,作為初學者的筆者難以消化,故在稍微會用軟件後撰寫本文,為自己留個筆記,同時希望能夠幫助到需要的人。 1.本文面向買了歐姆龍控制器

weixin_46005653的博客 1万+

隧道裂缝检测【C++PCL】

我们团队注重每一个细节,确保代码的可读性、可维护性和可扩展性达到最高标准。我们严格遵循行业最佳实践,采用模块化和面向对象的设计原则,使得我们的代码结构清晰且易于理解。我们的点云服务更是引以为傲。我们的技术团队拥有深厚的专业知识和丰富的经验,能够提供高度准确和高效的点云处理服务。无论是点云的获取、存储还是分析,我们都能够满足客户的需求,并提供出色的解决方案。我们的技术实力也是无与伦比的,拥有广泛的技术背景和深入的专业知识。

weixin_45196569的博客 848

基于RabbitMQ解决分布式事务

1、可查询操作:服务操作具有全局唯一的标识,操作唯一的确定的时间。 2、幂等操作:重复调用多次产生的业务结果与调用一次产生的结果相同。一是通过业务操作实现幂等性,二是系统缓存所有请求与处理的结果,最后是检测到重复请求之后,自动返回之前的处理结果。 3、TCC操作:Try阶段,尝试执行业务,完成所有业务的检查,实现一致性;预留必须的业务资源,实现准隔离性。Confirm阶段:真正的去执行业务,不做任何检查,仅适用Try阶段预留的业务资源,Confirm操作还要满足幂等性。Cancel阶段:取消执行业务,释放T

Tiger_Paul的博客 2686

数据架构师必看:大数据时代的架构演进与实践

数据架构是企业数据资产的“骨架”——它决定了数据能多快被处理、多准被分析、多安全被存储。本文将聚焦从传统架构到大数据架构的关键转折点,覆盖技术选型、典型场景、落地挑战三大核心命题,帮助读者建立“演进思维”而非“固定思维”。本文将按“历史演进→核心概念→技术原理→实战案例→趋势展望”的逻辑展开,用“超市仓库升级”贯穿始终,让抽象的技术概念具象化。传统数据仓库:精但小,适合结构化、批量分析。大数据架构:大但乱,适合全类型、海量数据存储。流批一体:解决实时+批量的效率问题。湖仓一体。

AI Agent Harness Engineering 913

rabbitmq mysql事务_RabbitMq解决分布式事务

1、分布式事务的常用解决方案(1)、基于数据库XA/JTA协议的方式;(需要数据库厂商的支持;java组件有atomikos等)(2)、异步校对数据的方式;(支付宝、微信支付主动查询支付转态、对账单的形式)(3)、基于可靠消息(MQ)的解决方案;(异步场景;通用性强;拓展性较高)(4)、TCC编程式解决方案。(严选、阿里、蚂蚁金服自己封装的DTX)2、使用rabbitmq解决分布式事务(1)、整体...

weixin_31693157的博客 530

EtherCAT主站SOEM -- 18 --Qt-Soem通过CSV模式(周期同步速度模式)控制一个电机转圈圈

以上就是 EtherCAT主站SOEM – 18 --Qt-Soem通过CSV模式(周期同步速度模式)控制一个电机转圈圈 的内容。有不明白的地方欢迎留言;有建议欢迎留言,我后面编写文档好改进。创作不容,如果文档对您有帮助,记得给个赞。

常驻客栈的博客--嵌入式EtherCAT 1211

大华 DSS 数字监控系统 itcBulletin SQL 注入漏洞复现

大华 DSs 数字监控系统是大华开发的一款安防视频监控系统,拥有实时监视、云台操作、录像回放、报警处理、设备管理等功能。大华 DSS存在SQL注入漏洞,攻击者 pota/services/itcBuletin 路由发送特殊构造的数据包,利用报错注入获取数据库敏感信息。攻击者除了可以利用 SQL注入漏词获取数据库中的信息例如,管理员后台密码、站点的用户人人信息)之外,甚至在高权限的情况可向服务器中写入木马,进一步获取服务器系统权限poc验证是否存在漏洞如果你想查询用户名和密码。

holyxp的博客 4001

SpringBoot整合消息中间件 RabbitMQ 第 10 篇 —— RabbitMQ 解决分布式事务(完结)

什么是分布式事务? 在微服务环境下,因为会根据不同的业务会拆分成不同的服务,比如会员服务、订单服务、商品服务等,每个服务都有自己独立的数据库,并且是独立运行,互不影响。在多数据源的情况下,两个服务相互通讯的时候,就会出现数据不一致的问题,从而出现分布式事务产生的原因。举例:某电商平台,用户先下单后,扣库存失败,那么将会导致超卖;如果下单不成功,扣库存成功,那么会导致少卖。 解决分布式事务基本思路 先了解一些概念:ACID原理、CAP、Base理论、柔性事务与刚性事务、理解最终一致性思想...

流放深圳 1304

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

基于RabbitMQ的分布式事务解决方案

一.分布式事物场景的一个错误示例 二.了解RabbitMQ 三.前言 - 分布式事物的几种解决方案 四.基于RabbitMQ的通用解决方案 整体设计思路 step1 - 可靠消息生产 - 记录消息发送 step2 - 可靠消息生产 - 修改消息发送状态 step3 - 可靠消息处理 - 正常处理 step4 - 可靠消息处理 - 消息重发 优缺点 ...

G0_hw 464

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

springboot分布式事务解决方案_基于RabbitMQ消息队列的分布式事务解决方案

1 极速了解MQ介绍Rabbitmg用于解决分布式事务必须掌握的5个核心概念一款分布式消息中间件,基于erlang语言开发, 具备语言级别的高并发处理能力。和Spring框架是同一家公司。 支持持久化、高可用核心5个概念:Queue: 真正存储数据的地方Exchange: 接收请求,转存数据Bind: 收到请求后存储到哪里消息生产者:发送数据的应用消息消费者: 取出数据处理的应用2、分布式事务问题...

weixin_39575648的博客 538

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

【RabbitMQ——消息应答机制——分布式事务解决方式】

NONE值是禁用发布确认模式,是默认值创建一个自己的消息确认类。

qq_45467608的博客 1908

项目总结|我是如何用RabbitMQ解决分布式事务问题的

文章目录前言本地事务和分布式事务简单一说本地事务分布式事务项目解决方案RabbitMQ延时队列(实现定时任务)解决了最终一致性,怎么保证消息可靠呢?总结 前言 回顾之前做的b2c项目,在订单服务那块,涉及到分布式事务的问题,情景是这样的:提交订单的时候,需要创建一笔订单,并且还需要调用远程库存服务进行库存锁定,等到支付成功之后将这个锁定的库存减掉。这里就涉及到远程调用的时候就可能会出现两个事务状态不一致的情况 本地事务和分布式事务 简单一说 本地事务: 它是在一个服务内的事务 分布式事务: 在微服务下,

MarkusZhang的博客 3253

rabbitmq 查询版本_基于rabbitmq解决分布式事务

分布式事务要解决的问题是保证二个数据库数据的一致性,本地事务ACID属于刚性事务,基于CAP理论,分布式事务的核心要点柔性事务,最终一致性。 基于rabbitmq解决分布式事务要点如下生产者采用发送方确认机制加上mandatory参数或者备份交换机,保证消息被正确地到达队列中。队列、交换机、消息都需要持久化(可以考虑镜像队列机制,如果业务不是那么重要,比如短信邮件通知)。消费端采用手动应答...

weixin_35755434的博客 157

基于RabbitMQ消息队列的分布式事务解决方案

1、5分钟了解MQ 介绍Rabbitmg用于解决分布式事务必须掌握的5个核心概念 一款分布式消息中间件,基于erlang语言开发, 具备语言级别的高并发处理能力。和Spring框架是同一家公司。 支持持久化、高可用 核心5个概念: Queue: 真正存储数据的地方 Exchange: 接收请求,转存数据 Bind: 收到请求后存储到哪里 消息生产者:发送数据的应用 消息消费者: 取出数据处理...

JavaEdge全是干货的技术号 6261
上一篇: spring 的 BeanFactory 和 ApplicationContext
下一篇: 腾讯正式开源 Spring Cloud Tencent,打造一站式微服务解决方案
Java5658
博客等级 码龄4年 169粉丝 107原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值