Mam pewne pytanie ... przykład: użytkownik kupi coś do jego USDPHP/MySQL - jak zapobiegać dwa wnioski * Aktualizacja
- Sprawdź swoją USD balansu
- odliczyć USD z jego konto
- Złóż zamówienie -> kolejka kolejność
- użytkownik dostaje swoją pozycję, a drugi ją USD
Pozwala dodawać, użytkownicy wykonują 5 żądań w tej samej sekundzie (bardzo szybko). Jest więc możliwe (i zdarza się), że 5 żądań jest uruchomionych. Ma tylko pieniądze na zakup tylko z 1 wniosku. Teraz żądania są tak szybkie, że skrypt sprawdza swoje saldo, ale nie jest tak szybki, że odejmuje on z jego konta pieniądze w wysokości . Tak więc prośby przejdą dwa razy! Jak go rozwiązać?
używam LOCK w mysql zanim zacznę tego procesu:
- IS_FREE_LOCK - sprawdzenie czy istnieje blokada dla tego użytkownika, jeśli nie -> 2.
- GET_LOCK - ustawia blokadę
- sprawi, że Zamówienie/transakcja
- RELEASE_LOCK - zwalnia blokadę
Ale to naprawdę nie działa. Czy istnieje inny sposób?
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));
}
Aktualizacja Testowany funkcję transakcji z wybranymi ... 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();
[** Proszę, nie używaj funkcji 'mysql_ *' w nowym kodzie **] (http://bit.ly/phpmsql). Nie są już utrzymywane [i są oficjalnie przestarzałe] (http://j.mp/XqV7Lp). Zobacz [** czerwone pudełko **] (http://j.mp/Te9zIL)? Dowiedz się więcej o [* przygotowanych wyciągach *] (http://j.mp/T9hLWi) i użyj [PDO] (http://php.net/pdo) lub [MySQLi] (http://php.net/ mysqli) - [ten artykuł] (http://j.mp/QEx8IB) pomoże ci zdecydować, który. – Kermit
Ktoś wie, co to oznacza: "użytkownik staje się jego przedmiotem, a drugi staje się jego USD"? Czy mieli na myśli "dostaje", a nie "staje się"? – ESRogs
Jak to jest * możliwe * prowadzenie witryny handlu online bez znajomości nawet * podstaw * dotyczących transakcji?!? – Massimo