I am building a system with nodeJS, sequelize, Mysql. It has a modules handles user purchasing game items. The logic is:
User initiate a request to buy an item
Server read user balance -
2.1 if balance is enough, issue user the game item and deduct the price of the item from user balance.
2.2 if balance is NOT enough, abort this request/transaction
The code I wrote to implement is:
return await Models.sequelize.transaction(async (t) => {
const wallet = await Models.Wallets.findOne({where: {user: userId}, transasction: t})
if (wallet.balance > item.price) {
await assignItemToUser(userId, t) // this is another sql with transaction
await wallet.decrement(
"balance",
{ by: item.price },
{ transaction: t }
);
} else {
throw new Error("cannot let user buy item")
}
})
Let's say user has balance $100, each item worth $90. I am wondering if this logic is secure enough to make sure I don't have a negative balance in a race condition where user triggers two buy action and both transaction read the balance $100 then resulting in user bought two items and with a negative balance (100 - 90 -90 = - 80) dollar?