forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   PHP / MySQL (http://forum.boolean.name/forumdisplay.php?f=135)
-   -   Определить количество записей, вставить запись? (http://forum.boolean.name/showthread.php?t=15518)

KRIK 21.09.2011 13:06

Определить количество записей, вставить запись?
 
Всем привет. Вот тут появилась задачка. Хочу узнать совета, как ее правильно решить. Имеется задача, чтобы сделать запись на прием. Но, на каждый день возможно записаться только для 10 человек. Я вижу решение этой задачи используя два запроса + php. Но как мне кажется, данное решение не правильно при ситуации когда будет уже записанно 9 человек и в один момент захотят записаться еще 2 или более человек.
Вот моё (неустраивающее меня решение)

Запрос 1. Получаем количество человек записанных на данный день в какую-то переменную в php (для примера день номер 1)
Код:

SELECT COUNT(id_записи),id_дня_для_записи FROM таблица_записей WHERE id_дня_для_записи=1 GROUP BY id_дня_для_записи
Запрос 2. Проводим проверку на сравнение количества человек записавшихся и возможных человек. После чего, если условие позволяет, записываем человека.
Код:

INSERT INTO таблица_записей .... VALUES(id_дня_для_записи, ....)
Ну и пошло поехало как говоря.

Но используя два запроса, как мне кажется, это во первых даст шанс записаться кому либо между ними, да и одним запросом это было бы лучше. Кто-что скажет по этому поводу?

moka 21.09.2011 14:03

Ответ: Определить количество записей, вставить запись!!!???
 
Хм, попробуй использовать LOCK на таблицу.

Для того чтобы проверить, сделай одного клиента, чтобы он поставил лок, запросил колличество записей, и далее пхп скрипт ждал бы 10 секунд, затем вставил бы запись, и анлочил таблицу.

Во время этих 10 секунд, таблица по идеи будет залочена, вторым клиентом попробуй сделать ту же операцию, без ожидания, и посмотри что скажет БД.

KRIK 21.09.2011 22:06

Ответ: Определить количество записей, вставить запись!!!???
 
А во время лока получается доступ имеет только один пользователь.. а чего другие тогда должны ждать 10 секунд получается!?) И кстати вот я все думаю, а реально ли объеденить те 2 запроса в один.. тогда как мне кажется распределение уже упадет на сервак, а не на наши проверки и плечи... только как вот скрестить слона с жирафом в голову пока не приходит...

moka 21.09.2011 22:11

Ответ: Определить количество записей, вставить запись!!!???
 
10 секунд задержка - это я предложил для проверки и теста на работоспособность. В реальном случае, никаких задержек не нужно. Транзакция займёт менее миллисекунды, никто и ничего ждать не будет.

"Скрестить" имеется ввиду запустить один скрипт INSERT. Но ведь вопрос стоит, делать его или нет, поэтому нужно какое-то условие.
Можно через жопу - создавать всё равно, но делать потом дополнительную проверку снова на Count. И таким образом узнав что нас тут не 10 а 11, отклонять. Но тут одно условие, если Count == 11 и ты есть последний, только тогда откланять. Т.к. это же самое сделает тот кто был 10ым, но он не последний, ему откланять не нужно.
Этот подход сработает, но это дополнительная транзакция, и вставка / удаление, что говнокод в бизнес логике.

ЛОК - лучший вариант.

KRIK 21.09.2011 22:30

Ответ: Определить количество записей, вставить запись!!!???
 
Ладно буду крутить вертеть)) Хоть гляну для примера чего будет)) И про 10 секунд я понял что речь не про них. Просто на примере еще не глядел)) Спасибо!

IGR 22.09.2011 02:31

Ответ: Определить количество записей, вставить запись!!!???
 
сделал бы два запрса и непарился !!
Первый проверил возможность добавления, если уже 10 то написал бы юзеру - извините запись на прием окончена !!
Если все ок - инсерт записи !!

moka 22.09.2011 04:00

Ответ: Определить количество записей, вставить запись!!!???
 
Цитата:

Сообщение от IGR (Сообщение 203045)
сделал бы два запрса и непарился !!
Первый проверил возможность добавления, если уже 10 то написал бы юзеру - извините запись на прием окончена !!
Если все ок - инсерт записи !!

Топик не читай - сразу отвечай.

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

KRIK 22.09.2011 09:22

Ответ: Определить количество записей, вставить запись!!!???
 
Ну будет странно, если вдруг положено 10 человек, а вдруг когда-нибудь 11 пролезет) это не есть хорошо)

KRIK 22.09.2011 10:41

Ответ: Определить количество записей, вставить запись!!!???
 
Сделал для теста вот такую наброску.

PHP код:

$model->lock();
print_r($model->countForDay());
sleep(10);
$model->unlock(); 

Где функции вот такие:
PHP код:

function lock()
    {
        
$query 'LOCK TABLES #__zapis WRITE';
        
$res mysql_query($query);
        return 
$res;
    }
    
    function 
countForDay()
    {
        
$query 'SELECT count(id_zapis) FROM #__zapis WHERE id_dnya=1';
        
$count mysql_query($query);
        return 
$count;
    }
    function 
unlock()
    {
        
$query 'UNLOCK TABLES';
        
$res mysql_query($query);
        return 
$res;
    } 

Все работает. Название таблиц просто не совпадало. А так прям как надо))

cyberblut 22.09.2011 13:19

Ответ: Определить количество записей, вставить запись!!!???
 
PHP код:

INSERT INTO `YOUR_TABLE` (field1field2
SELECT 'value1''value2' 
  
FROM DUAL 
  WHERE 
(SELECT COUNT(id) as cnt FROM `YOUR_TABLEWHERE date 'SELECTED_DATE') < 9

- DUAL - виртуальная таблица, используется, если не нужно делать выборку из реальной
- value1 и value2 нужно передать напрямую из скрипта
- date - поле в которое записывается дата прихода на приём, нужно проверять в формате yyyy-mm-dd (т.е. без времени, просто день)
---
Я бы делал по следующему алгоритму:
- ввёл бы дополнительное поле request_id и сделал бы уникальным индексом
- перед запросом бы генерил уникальный ключ: $key = md5(rand(0, 999) . microtime() . date('yyyymmddHHiiss') . $personName);
- писал бы ключ внутри запроса в базу
- после проверял бы селектом, есть такой ключ в базе или нет
- если есть - запись прошла успешно

Нужно конечно ещё ловить ошибку на уникальность при инсерте и перегенеривать тогда ключ. Но я крайне сомневаюсь в возможности появления такой ситуации :)

KRIK 22.09.2011 21:57

Ответ: Определить количество записей, вставить запись!!!???
 
А разве если этот запрос выполнить к примеру через mysql_query() мы не получим результата
выполнился запрос или нет? Помоему если мне не отказывает память мы получим false или true на выходе.

cyberblut 23.09.2011 10:34

Ответ: Определить количество записей, вставить запись!!!???
 
Не получим :)
mysql_query() возвращает ресурс результата (или true), если в запросе НЕТ ОШИБОК. Или соответственно false, если ошибки есть.
Поэтому в данном случае, если не накосячишь с самим запросом, у тебя всегда будет true, а значит нужно будет результат проверять.

shybovycha 26.09.2011 22:49

Ответ: Определить количество записей, вставить запись!!!???
 
Учите основы SQL: используйте транзакции. Кроме транзакции, придется использовать либо сохраненную процедуру, либо триггер BEFORE INSERT. С процедурой проще:

Код:

DELIMITER //;
CREATE PROCEDURE add()
BEGIN
SELECT @x = COUNT(id) FROM table;
IF @x < 10 THEN
INSERT INTO table ([fields]) VALUES ([field values]);
END IF;
END;
DELIMITER ;//

Потом - собсно транзакция и вызов процедуры:

Код:

START TRANSACTION;
CALL add();
COMMIT;

Объяснять как работают транзакции не буду. Скажу лишь, что коль в транзакции ничего не добавилось в таблицу - ничего страшного. А вот если ошибка вылезет - данные не изменятся. В этом и профит транзакций (кроме параллельных операций).

И да, LOCKS - наверное самая забавная идея, которую довелось слышать за неделю мне =)

Для тех, кто не понял сарказма: запросы следует выполнять лишь тогда, когда?

а) нужно получить данные
б) нужно сохранить уже готовые данные

С триггером придется поиграться...

KRIK 02.10.2011 20:17

Ответ: Определить количество записей, вставить запись!!!???
 
Хронимые процедуры в MySQL ? А где их там смотреть то?

shybovycha 02.10.2011 20:34

Ответ: Определить количество записей, вставить запись!!!???
 
Цитата:

Сообщение от KRIK (Сообщение 204264)
Хронимые процедуры в MySQL ? А где их там смотреть то?

Ни разу не понял смысла псто...


Часовой пояс GMT +4, время: 08:51.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot