|
автор: Настя (07.09.2005 в 23:24) |
|
| Подскажите, плиз, как тут быть.
Пользователь запускает скрипт, который:
- смотрит в одной таблице mysql последний ID и загружает туда + в другую таблицу некие строки, завязанные на этот ID+1
Проблема в том, что если скрипт запускают несколько пользователей одновременно, то последний ID у них оказывается одинаковым (т.к. ни один из них еще не загрузил новые строки, а только успел считать последний ID). И даже если использовать last_insert_id, как я понимаю, будет то же самое.
Можно ли этого избежать? (При этом нужно, чтобы таблицы не блокировались на чтение, т.к. есть другие скрипты, которые постоянно их читают). | |
|
|
|
|
|
|
|
для: Настя
(07.09.2005 в 23:24)
| | Че то не очень понятно. Если установлен атрибут поля auto_increment, то никаких проблем не будет MySQL сама сгенерирует уникальный id. А если используется конструкция вида
UPDATE tbl SET id = id +1
|
то проблем вообщем тоже не должно быть. | |
|
|
|
|
автор: Настя (07.09.2005 в 23:39) |
|
|
для: Евгений Петров
(07.09.2005 в 23:28)
| | А какая разница?
Вот, допустим, идет этот auto_increment. С первой таблицей все ок.
Идем ко второй, запрашиваем last_insert_id первой таблицы - пишем строку во 2 таблицу (использую этот номер и первой таблицы).
А между тем в 1 таблицу уже мог кто-то другой еще 1 строчку записать и last_insert_id будет уже не тот. И свяжутся не те строки двух таблиц.
Так или нет? | |
|
|
|
|
|
|
|
для: Настя
(07.09.2005 в 23:39)
| | Если ты имеешь ввиду, что в промежутке времени между занесением данных в первую таблицу и вызовом функции last_insert_id, кто то может занести что то в БД и id будет другим, то нет MySQL расчитан на то что с ним могут одновременно работать несколько пользователей поэтому он сгенерирует именно тот id который был занесен именно тобой. Хотя даже если бы такого не было бы предусмотрено, то я думаю вряд ли за какие то 10 000 доли секунды а то и меньше кто то успеет чего нибудь занести. | |
|
|
|
|
автор: Настя (07.09.2005 в 23:54) |
|
|
для: Евгений Петров
(07.09.2005 в 23:49)
| | Успеет-успеет, проверено.
Можно попродробнее, а что значит, "занесен именно тобой"? В смысле запущенным скриптом у конкретного пользователя? А если одновременно этот же скрипт запускает другой пользователь, то у ему выдастся его last_insert_id, даже если в таблице он уже далеко не last?
Получается last_insert_id относится как бы к пользователя, а не к таблице? Т.е. это не поледний id таблицы, а последний id, записанный данным пользователем? | |
|
|
|
|
|
|
|
для: Настя
(07.09.2005 в 23:54)
| | Я не уверен, но помоему функция last_insert_id возвращает не последний id вовсей таблице, а тот который был сгенерирован при последнем занесении в базу записи в пределах выполнения скрипта.
Успеет-успеет, проверено.
Вообще говоря странно, выложи тот скрипт, который такое делает. | |
|
|
|
|
автор: Настя (08.09.2005 в 00:12) |
|
|
для: Евгений Петров
(08.09.2005 в 00:01)
| | $query="SELECT MAX(ficid) FROM 'fanfics'";
$result=mysql_query($query,$dblink);
$row=mysql_fetch_row($result);
$ficid=$row[0]+1;
$query="INSERT INTO 'fanfics' ( 'ficid' , 'auth_id' , 'ficname' , 'mainpers' , 'p2' , 'p3' , 'p4' , 'p5' , 'genre' , 'genre2' , 'genre3' , 'raiting' , 'summary' , 'chapters' , 'startdate' , 'changedate' , 'source' , 'status' , 'stars' , 'mark' , 'people' , 'reviews' , 'views' , 'podpiska' , 'forum_topic' ) VALUES ('$ficid', '$id', '$ficname', '$mainpers', '$dp[0]', '$dp[1]', '$dp[2]', '$dp[3]', '$genre[0]', '$genre[1]', '$genre[2]', '$raiting', '$summary', '1', '$date2', '$date2' , '$source', '$status' , '0', '0', '0', '0', '0', '0', '0');";
$result=mysql_query($query,$dblink);
$query="INSERT INTO 'chapters' ('fic_id' , 'chap_number' , 'chap_name' , 'chap_text', 'ip') VALUES ('$ficid', '1', '$chapname', '$fictext', '$ip2');";
if (!($result=mysql_query($query,$dblink))) {echo mysql_error();}
Как-то так... (Max) из первой базы успевают взять несколько пользователей, и они сталкиваются, когда пытаются писать во 2 таблицу. | |
|
|
|
|
|
|
|
для: Настя
(08.09.2005 в 00:12)
| | Евгений все верно сказал. надо использовать last_insert_id:
<?
$query="INSERT INTO fanfics ( 'ficid' , 'auth_id' , 'ficname' , 'mainpers' , 'p2' , 'p3' , 'p4' , 'p5' , 'genre' , 'genre2' , 'genre3' , 'raiting' , 'summary' , 'chapters' , 'startdate' , 'changedate' , 'source' , 'status' , 'stars' , 'mark' , 'people' , 'reviews' , 'views' , 'podpiska' , 'forum_topic' ) VALUES (0, '$id', '$ficname', '$mainpers', '$dp[0]', '$dp[1]', '$dp[2]', '$dp[3]', '$genre[0]', '$genre[1]', '$genre[2]', '$raiting', '$summary', '1', '$date2', '$date2' , '$source', '$status' , '0', '0', '0', '0', '0', '0', '0');";
$result=mysql_query($query,$dblink);
$ficid=last_insert_id();
$query="INSERT INTO 'chapters' ('fic_id' , 'chap_number' , 'chap_name' , 'chap_text', 'ip') VALUES ('$ficid', '1', '$chapname', '$fictext', '$ip2');";
if (!($result=mysql_query($query,$dblink))) {echo mysql_error();}
?>
|
А первый запрос можно смело выкинуть. Чтобы это работало, в таблице fanfics поле ficid должно иметь атрибут auto_increment | |
|
|
|
|
автор: Настя (08.09.2005 в 23:08) |
|
|
для: Loki
(08.09.2005 в 09:58)
| | Т.е. last_insert_id действительно относится к скрипту, запущенному конкретным пользователем, а не к таблице, так? | |
|
|
|
|
|
|
|
для: Настя
(08.09.2005 в 23:08)
| | Вообще фиг его знает, я прочитал мануал по MySQL так там вроде написано, что данные сохраняются на сервере т.е. last_insert_id() возвращает id последнего запроса к таблице вообще. Хотя если это так, то я тогда не понимаю смысл этой функции. Толку с неё... | |
|
|
|
|
автор: Настя (08.09.2005 в 23:41) |
|
|
для: Евгений Петров
(08.09.2005 в 23:15)
| | >Вообще фиг его знает, я прочитал мануал по MySQL так там
>вроде написано, что данные сохраняются на сервере т.е.
>last_insert_id() возвращает id последнего запроса к таблице
>вообще. Хотя если это так, то я тогда не понимаю смысл этой
>функции. Толку с неё...
Действительно?..
Может, кто-то еще знает? Ау? Просто если эта функция относится к таблице, а не к пользователю, то моя проблема остается - то, что пользователь может пролучить чужой id (тот, котрый уже прошел следом за его). | |
|
|
|
|
|
|
|
для: Настя
(08.09.2005 в 23:41)
| | В том коде что ты привела last_insert_id() нигде не вызывается. Где она используется? | |
|
|
|
|
автор: Настя (09.09.2005 в 00:22) |
|
|
для: Евгений Петров
(09.09.2005 в 00:16)
| | Потому что в моем случае без разницы, что max(), что last_id()
Считай, я его использую, после того, как загружаю строку в таблицу fanfics, чтобы получить $ficid | |
|
|
|
|
|
|
|
для: Евгений Петров
(09.09.2005 в 00:16)
| | Хотя нет все правильно ч только что проверил.
Запустил скрипт:
<?
mysql_query("INSERT INTO tbl(text) VALUES('Строка')");
sleep(10);
echo mysql_insert_id();
?>
|
И за те 10 секунд которые скрипт спит занес в таблицу ещё одну запись и сркипт выдал мне именно тот id который был сгенерирован именно этим скриптом. Т.е. все должно работать проблема (если она есть) не в этом. | |
|
|
|
|
|
|
|
для: Настя
(08.09.2005 в 23:41)
| | Не очень понятно в чём проблема last_insert_id () - возвращает счётчик таблицы, операция вставки атомарна, поэтому никаких сбоев не должно быть, если значение last_insert_id используется после, то следует прибегать либо к блокировке таблицы при помощи LOCK TABLES, либо к транзакциям. К сожалению, транзакции в MyISAM не доступны и необходимо использовать InnoDB, которая в несколько раз медленнее таблицы MyISAM. | |
|
|
|
|
|
|
|
для: cheops
(09.09.2005 в 01:30)
| | Т.е. если кто то успеет добавить что нибудь в БД то last_insert_id будет другим? | |
|
|
|
|
|
|
|
для: Евгений Петров
(09.09.2005 в 16:54)
| | Хм... А в смысле не успеет? | |
|
|
|
|
|
|
|
для: cheops
(09.09.2005 в 19:59)
| | Ну вот например вставляется запись в таблицу а потом где то извлекается значение mysql_insert_id(). Так вот если в промежутке времени между запросом и вызовом mysql_insert_id() кто нибудь занесет в б.д. еще одно значение, то изменится ли id или нет. Я лично думаю что нет, т.к. опытным путем проверил, что id возвращается именно тот который был сгенерирован последним запросом а ТЕКУЩЕМ скрипте, а не вообще запросом к б.д. | |
|
|
|
|
|
|
|
для: Евгений Петров
(09.09.2005 в 21:17)
| | Более того, last_insert_id относится не просто к текущему скрипту, но и к текущему запросу. То есть если выполнить еще какой-то запрос после добавления записи, то last_insert_id уже не вернет значение (читал об этом - сам не пробовал:) | |
|
|
|
|
|
|
|
для: Евгений Петров
(09.09.2005 в 21:17)
| | Ну да не изменится... так и не нужно чтобы это значение изменялось, так как оно предназначено для организации связи между таблицами, т.е. если вы вставили значение с AUTO_INCREMENT вы можете его узнать для того, чтобы поместить это значение в качестве вторичного ключа в другую таблицу. Если значение будет "плыть" никакой связи не получится. Так ведь больше и надобности нет - число записей всегда можно узнать при помощи функции count() - ей и следует пользоваться и ничем другим, а новые значения AUTO_INCREMENT - это внутреннее дело базы данных. | |
|
|
|
|