We are building a medium scale fintech product on Laravel where users will be able to load money into their wallet, transfer money to any other wallet or settle funds to any bank account using payout APIs.
To add funds, the user is subject to get the approval from the admins for every amount he deposits into his wallet. Once the admin approves, money gets reflected in his wallet.
The issue is, often times, the admin approves the fund request at the same time when the user is transferring money to someone or sending a payout.
We have different functions that get invoked on fund request approval, payout and wallet transfer respectively. These functions are being called concurrently in such instances. This is causing huge issues!
我们正在Laravel上建立一个中等规模的金融科技产品,用户将能够将钱装入他们的钱包,将钱转移到任何其他钱包,或者使用支付API将资金结算到任何银行账户。要添加资金,用户必须获得管理员的批准,才能将每一笔钱存入他的钱包。一旦管理员批准,钱就会反映在他的钱包里。问题是,通常情况下,管理员批准资金请求的同时,用户正在向某人转账或发送支出。我们有不同的函数,分别在资金申请审批、支付和钱包转账时调用。在这种情况下,这些函数被并发调用。这引起了很大的问题!
For example, if user A is having $3000 in his wallet and he settles $2000 to someones account but at that exact time, admin approves his fund request of $5000. In this case, the fund request function and payout function both get invoked concurrently. And we get data like this (data is in descending order of timestamp):
例如,如果用户A的钱包中有3000美元,他向某人的帐户结算了2000美元,但恰好在那个时间,管理员批准了他5000美元的资金请求。在这种情况下,资金请求函数和支出函数都被同时调用。我们得到这样的数据(数据按时间戳的降序排列):
user |
tranxn_id |
debit_amount |
credit_amount |
opening_balance |
closing_balance |
timestamp |
140 |
PYT123454 |
2000 |
0 |
3000 |
1000 |
2023-04-16 02:00:48 |
140 |
FND876954 |
0 |
5000 |
3000 |
8000 |
2023-04-16 02:00:48 |
You can see, even if he received funds from admin worth $5000 still his effective wallet balance after payout was just $1000.
I have used DB transactions, locking and what not but I am missing out something. Please help me with your valuable words.
EDIT
I'm attaching my code snippet to better understand what I'm trying to do.
你可以看到,即使他从管理员那里收到了价值5000美元的资金,他的实际钱包余额在支付后仍然只有1000美元。我使用过数据库事务、锁定等等,但我遗漏了一些东西。请帮我写一些有价值的话。编辑我附上了我的代码片段,以便更好地理解我想要做的事情。
DB::transaction(function () use ($amount, $service, $service_type, $user_id, $opening_balance, $transaction_id, $closing_balance, $metadata, $credit) {
DB::table('transactions')->insert([
'debit_amount' => $amount,
'transaction_for' => $service,
'user_id' => $user_id,
'trigered_by' => $user_id,
'credit_amount' => $credit,
'opening_balance' => $opening_balance,
'closing_balance' => $closing_balance,
'service_type' => $service_type,
'metadata' => $metadata,
'transaction_id' => $transaction_id,
'created_at' => now(),
'updated_at' => now()
]);
$user = User::lockForUpdate()->find($user_id);
$user->update(['wallet' => $closing_balance]);
}, 2);
First, we are adding an entry in the `transactions` table and then we are updating the user's wallet
更多回答
Please check out both answers to the duplicate question.
请核对重复问题的两个答案。
You want to make sure you are using transactions on the controller. Using transactions can help you address the issue of concurrent modifications to the same field in your database. Transactions provide a way to ensure data consistency and integrity when multiple requests are trying to modify the same data concurrently.
您需要确保使用的是控制器上的事务。使用事务可以帮助您解决对数据库中同一字段进行并发修改的问题。当多个请求试图同时修改同一数据时,事务提供了一种确保数据一致性和完整性的方法。
You can check this post about transactions in Laravel:
https://laravel.io/articles/using-database-transactions-to-write-safer-laravel-code
你可以在Laravel上查看这篇关于交易的帖子:https://laravel.io/articles/using-database-transactions-to-write-safer-laravel-code
更多回答
I'm already using DB::transaction
but still facing this issue. I'm updating my question with my code snippet
我已经在使用DB::Transaction,但仍然面临这个问题。我正在使用代码片段更新我的问题
Unfortunately, this answer echoes the common misconception that transactions help with concurrency. No, they are not. Their purpose is to ensure that either all modifications are done or none at all. Concurrency is handled through locks. The reason for the misconception of transactiins handling concurrency is that many database locks are released when a transaction finishes.
不幸的是,这个答案呼应了一种常见的误解,即事务有助于并发。不,他们不是。它们的目的是确保要么完成所有修改,要么根本不修改。并发性是通过锁处理的。对事务处理并发性产生误解的原因是,当事务完成时,许多数据库锁被释放。
我是一名优秀的程序员,十分优秀!