春季交易多线程问题

发布于 2025-01-18 17:14:58 字数 2213 浏览 5 评论 0原文

我正在从事付款服务,然后在付款过程中扣除产品的股票扣除问题。我还没有弄清楚如何为整体应用程序和分布式应用程序做到这一点。

我正在使用以下技术堆栈;

  • MySQL数据库
  • Spring Boot框架
  • Hikari连接池

这些是实体。

付款实体,

@Entity
public class Payment {

    private static final int HASH = 17;

    @Id
    @GeneratedValue
    private Long id;
    private BigDecimal price;
    private String bankResponse;
    private String integrationId;

产品实体,


public class Product {

    private static final int HASH = 29;
    
    @Id
    @GeneratedValue
    private Long id;
    
    private String name;
    
    private String description;
    
    private Integer remainingStockCount;
    
    private BigDecimal price;
    
    @Version
    private Integer version;

就我而言,

要求是

  1. 产品不应以其股票的价格出售。
  2. 如果股票耗尽,则同时支付同一产品的客户不应购买该产品。 (即,如果剩下2个股票,并且有3个客户同时付款,那么第一个成功应该购买该产品,而第三个客户应以适当的消息失败。)
  3. 也有一种异步方法可以在扣除股票之后或之前向银行付款,请考虑。

我在那里有很多问题,

  1. 对于单层应用,我认为我可以通过春季交易注释来实现它,但是我们需要考虑使用多线程的解决方案,所以我不知道我应该如何扣除特定产品的库存,对于我上面提到的情况(第二种情况)。
  2. 对于分布式解决方案,我们有很多服务器,并且在类似服务器的容器中运行的许多应用程序,如果我使用春季交易式注释,我是否会错过某些内容,或者如何为分布式系统进行操作?

为了简单起见,我在这里打破了测试方法。

private void runPaymentForProduct(ProcessType processType) {
        List<CompletableFuture> futures = new ArrayList<>();
        for (int i = 0; i < 15; i++) {
            CompletableFuture future = getFuture();
            futures.add(future);
        }
        futures.forEach(f -> CompletableFuture.allOf(f).join());
}

private CompletableFuture getFuture() {
        return CompletableFuture.runAsync(() -> {
                            productPaymentService.pay(ID);
                }
        );
}
  1. 我有付款方式并添加了 @transactional注释,但是在这种交易方法中也称为异步方法,因此我无法解决如何和谐地适应这两个过程。
  2. 我不想使用一些并发收集或锁定机制(读取锁定,同步),因为即使我们使用单片应用程序,我们也可以扩展服务器,这就是为什么如果我们实现了基于单个服务器的解决方案,则不始终如一地与其他服务器一起使用。
  3. 顺便说一句,如果我们实现此解决方案,我们假设有100个用户称此端点为此,因此我们需要公平对待每个用户,并立即给出响应。
  4. 当您回答这些问题时,可以将解决方案分为两个部分,例如单片和分发?
  5. 顺便说一句,我无法更改Hikari CP的设置,例如增加连接的超时或增加池的大小,因为我们需要通过其他方式解决。
  6. 我正在使用一种乐观的锁定机制,这就是为什么产品实体具有@version注释的原因。

I'm working on Payment Services, then I have an issue with the product's stock deduction during the payment process. I haven't figured out how I will do this for monolithic apps and distributed apps.

I'm using the below technology stacks;

  • MySQL Database
  • Spring Boot Framework
  • Hikari Connection pool

These are entities.

Payment entity,

@Entity
public class Payment {

    private static final int HASH = 17;

    @Id
    @GeneratedValue
    private Long id;
    private BigDecimal price;
    private String bankResponse;
    private String integrationId;

Product Entity,


public class Product {

    private static final int HASH = 29;
    
    @Id
    @GeneratedValue
    private Long id;
    
    private String name;
    
    private String description;
    
    private Integer remainingStockCount;
    
    private BigDecimal price;
    
    @Version
    private Integer version;

In my case,

Requirement is,

  1. A product should not be sold for more than its stock.
  2. Customers paying for the same product at the same time should not buy the product if the stock is depleted. (i.e. if there are 2 stocks left and 3 customers pay at the same time, first 2 successful should buy the product and the 3rd one should fail with an appropriate message.)
  3. There is an async method to pay to the bank also after or before stock's deduction, please also consider it.

I have a lot of questions in there,

  1. For a monolithic application, I think I can achieve it with Spring Transactional annotation, but we need to consider the solution with multithreading, so I don't know how I should deduct stock of the specific product, for the case that I mentioned above (second case).
  2. For the distributed solution, we have a lot of servers, and a lot of applications that run in the server-like container, if I use Spring Transactional annotation, do I miss something or how can I do it for distributed systems?

For the sake of simplicity, I'm breaking my test methods here;

private void runPaymentForProduct(ProcessType processType) {
        List<CompletableFuture> futures = new ArrayList<>();
        for (int i = 0; i < 15; i++) {
            CompletableFuture future = getFuture();
            futures.add(future);
        }
        futures.forEach(f -> CompletableFuture.allOf(f).join());
}

private CompletableFuture getFuture() {
        return CompletableFuture.runAsync(() -> {
                            productPaymentService.pay(ID);
                }
        );
}
  1. I have the payment method and added @Transactional annotation, but there is also an async method which is called in this transactional method, so I couldn't solve how I adapt these two processes harmonically.
  2. I didn't want to use some concurrent collections or locking mechanism (read-write lock, synchronized) because even if we use monolithic applications, we can scale out our servers, that's why if we implement the single server-based solution, then it doesn't work with other servers together consistently.
  3. By the way, if we implement this solution, let's assume that there are 100 users who call this endpoint, so we need to treat each user fairly, and give a response immediately.
  4. When you answer these, could you please split the solution into two parts such as monolithic and distributed?
  5. By the way, I can't change Hikari cp's settings like increasing the connection's timeout or increasing's the pool's size because we need to solve with other ways.
  6. I'm using an optimistic lock mechanism, that's why Product Entity has @Version annotation.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

自此以后,行同陌路 2025-01-25 17:14:58

您可以查看发件箱模式,以防分布式架构以原子方式执行事务并获得最大保证,

请参阅:https://debezium.io/blog/2019/02/19/reliable-microservices-data-exchange-with-the-outbox-pattern/

对于整体,我觉得你应该有应用程序事件将按顺序运行。

You can have a look at Outbox pattern in case of distributed archiecture to do the transactions atomically and have maximum guarantees

refer: https://debezium.io/blog/2019/02/19/reliable-microservices-data-exchange-with-the-outbox-pattern/

For monolithic still I feel you should have application events that will be run in a sequence.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文