2016-04-04 2 views
0

Я разработал игру, которая работает с php и jquery через ajax.Разрешить только одну открытую запись за раз в mysql

По существу, когда запрос делается сервером, сервер создаст новую игру, если ее еще нет. Моя таблица базы данных для игр выглядит следующим образом:

id | closed | time 

Где закрыт будет установлен в 1 раз игра закончена, и время является Отметка времени Unix, когда игра была создана.

Теперь важно то, что в любой момент времени в таблице может быть только 1 игра с закрытым = 0.

Для этого я использую следующий код PHP

$query = "SELECT id FROM games WHERE closed = '0' LIMIT 1"; 
$result = $this->database->query($query); 
if ($result->num_rows == 0) { 
    $query = "INSERT INTO games_roulette SET time = '".time()."'"; 
    $result = $this->database->query($query); 
    return $this->database->insert_id; 
} else { 
    return false; 
} 

Вещь иногда 2 игры будут созданы, я полагаю, из-за 2 запросы отправляются в одно и то же время, как значения времени всегда то же самое, когда открыто 2 игры.

Есть ли способ, которым я могу иметь 100% уверенность, что в таблице никогда не будет 2 игры с закрытыми = 0?

+0

вы можете заблокировать таблицу перед выбором и разблокировать ее после вставки. я бы поспорил, есть лучшие варианты –

ответ

1

Вероятная причина, по которой вы в итоге получаете 2 записи, - это, как вы подозреваете, параллелизм. Если 2 процесса отдельно запускают запрос SELECT, они оба получат зеленый свет для продолжения, и оба они будут запускать INSERT. Таким образом, вы получаете 2 (или более!) Таких строк.

Традиционно, вы бы использовать транзакции или замки, чтобы избежать этого, но есть также SQL «трюк», который позволил бы один атомный запрос для достижения этой цели:

 
INSERT INTO 
    game_roulette 
SELECT NULL, x.closed, NOW() 
    FROM 
    (SELECT '0' as closed) x 
    LEFT JOIN game_roulette g ON x.closed = g.closed 
    WHERE 
    g.id IS NULL 

Просто, чтобы объяснить, как это работает: это синтаксис INSERT ... SELECT, где запрос SELECT дает результат, если нет строки, где game_roulette.closed - '0'. Это, в свою очередь, делается путем создания таблицы с одной строкой x, а затем делает LEFT JOIN против game_roulette на столбце closed и использует ограничение g.id IS NULL.

После завершения этого запроса приложение при необходимости может проверить результат INSERT, как это было бы сделано для любого другого, чтобы узнать, были ли вставлены какие-либо строки (ы).

Примечание: если вы делаете это на большой таблице, вы должны измерить производительность запроса и/или убедиться, что есть индекс в столбце closed, и он привыкает.

+0

Это именно то, что я хотел. Спасибо. –

Смежные вопросы