我有一些问题......例如:用户会为他的美元购买东西
可以说,用户在同一秒内发出5个请求(非常快).因此,有可能(并且正在发生)5个请求正在运行.他只有1个请求才能购买.现在请求是如此之快,以至于脚本检查了他的余额,但速度不是很快,它从他的帐户中扣除了钱.所以请求将通过两次!怎么解决?
我在开始这个过程之前在mysql中使用LOCK:
但这并没有真正起作用.还有另外一种方法吗?
function lock($id) {
mysql_query("SELECT GET_LOCK('$id', 60) AS 'GetLock'");
}
function is_free($id) {
$query = mysql_query("SELECT IS_FREE_LOCK('$id') AS 'free'");
$row = mysql_fetch_assoc($query);
if($row['free']) {
return true;
} else {
return false;
}
}
function release_lock($id) {
mysql_query("SELECT RELEASE_LOCK('$id')");
}
function account_balance($id) {
$stmt = $db->prepare("SELECT USD FROM bitcoin_user_n WHERE id = ?");
$stmt->execute(array($id));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
return $row['USD'];
}
if(is_free(get_user_id())) {
lock(get_user_id());
if(account_balance(get_user_id()) < str2num($_POST['amount'])) {
echo "error, not enough money";
} else {
$stmt = $db->prepare("UPDATE user SET USD = USD - ? WHERE id = ?");
$stmt->execute(array(str2num($_POST['amount']), get_user_id()));
$stmt = $db->prepare("INSERT INTO offer (user_id, type, price, amount) VALUES (?, ?, ?, ?)");
$stmt->execute(array(get_user_id(), 2, str2num($_POST['amount']), 0));
}
Run Code Online (Sandbox Code Playgroud)
更新 使用SELECT ... FOR UPDATE测试事务功能
$db->beginTransaction();
$stmt = $db->prepare("SELECT value, id2 FROM test WHERE id = ? FOR UPDATE");
$stmt->execute(array(1));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if($row['value'] > 1) {
sleep(5);
$stmt = $db->prepare('UPDATE test SET value = value - 5 WHERE id = 1');
$stmt->execute();
$stmt = $db->prepare('UPDATE test SET value = value + 5 WHERE id = 2');
$stmt->execute();
echo "did have enough money";
} else {
echo "no money";
}
$db->commit();
Run Code Online (Sandbox Code Playgroud)
小智 25
首先,你必须使用交易,但这还不够.在您的交易中,您可以使用SELECT FOR UPDATE
.
它基本上是在说,"我要更新我正在选择的记录",所以它设置了相同的锁定UPDATE
.但请记住,这必须在关闭自动提交的事务中发生.
使用TRANSACTION,如果失败,您可以回滚.
例如,假设当前余额为20美元.
Connection A Connection B
======================= ===========================
BEGIN TRANSACTION
BEGIN TRANSACTION
SELECT AccountBalance
SELECT AccountBalance
--returns $20
--sufficient balance,
--proceed with purchase
--returns $20
--sufficient balance,
--proceed with purchase
--update acquires exclusive lock
UPDATE SET AccountBalance
= AccountBalance - 20
--update blocked due
UPDATE SET AccountBalance
= AccountBalance - 20
--order complete
COMMIT TRANSACTION
--update proceeds
--database triggers
--constraint violation
--"AccountBalance >= 0"
ROLLBACK TRANSACTION
Run Code Online (Sandbox Code Playgroud)
小智 5
这就是我多年前做过的事情.
results = query("UPDATE table SET value=value-5 WHERE value>=5 AND ID=1")
if (results == 1) YEY!
Run Code Online (Sandbox Code Playgroud)
(这仍然是一种可靠的方法吗?)
归档时间: |
|
查看次数: |
25961 次 |
最近记录: |