У меня есть ротатор всплывающих окон, который подсчитывает ip пользователя unic пользователя в день (для дубликатов в тот же день не разрешен IP-адрес дубликата)
$userip = mysql_real_escape_string($_SERVER['REMOTE_ADDR']); $date = date('Ym-d'); $result = mysql_query("SELECT `ip` FROM `popupip` where ip = '$userip' AND userid = $secid AND date='$date'"); $num = mysql_num_rows($result); if ($num > 0) { // **it is duplicate Do not insert it in popupip table** }else{ // **it is not duplicate ip insert it in popupip table** }
выше код является примером. Я знаю полный код.
но когда я смотрю на свою таблицу popupip
phpmyadmin, есть несколько дубликатов ip для пользователя (тот же самый ip-адрес для пользователя в ту же дату)
как это возможно?
Дополнительная информация: в popupip
userid
есть int (11), date
– «тип даты, такой как 2014-05-30», а ip
– varchar. эта страница может открываться «как можно быстрее в одно и то же время» по всплывающим страницам. существует ли связь между быстрым открытием страницы в одно и то же время пользователем и дублированием создания ip? есть ли ошибка в MySQL? (может быть, большая ошибка !!!!)
Да, это возможно. Это классический случай состояния гонки.
Краткое объяснение:
Существует вероятность того, что 2 запроса одновременно пройдут первую проверку, получите $num == 0
и оба вставляют новую строку.
Чтобы устранить это, вам необходимо создать ограничение UNIQUE
которое охватывает (user_id, ip, date)
столбцы
Длительное объяснение:
Если несколько запросов поступают из одного и того же ip одновременно, возможно, что некоторые из них выполняют запрос выбора, прежде чем какой-либо из них выполнит запрос на вставку (в результате получится несколько вставок с тем же ip и датой).
Решением для этого является создание индекса UNIQUE с ip, user_id и датой (вы можете легко сделать это в phpMyAdmin, выполнив запрос ниже):
ALTER TABLE `popupip` ADD UNIQUE (`ip`, `user_id`, `date`);
После этого вы можете оптимизировать свой код и просто выполнить запрос «INSERT IGNORE», который только вставляет, если комбинация (ip, user_id, date) еще не существует в таблице:
mysql_query("INSERT IGNORE INTO `popupip` (`ip`, `user_id`, `date`) VALUES ('$userip', $secid, '$date');");
С помощью этого решения вам не нужно делать дополнительный запрос «SELECT» или «if», чтобы проверить, есть ли результаты.