Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
PHP 5. На примерах. Авторы: Кузнецов М.В., Симдянов И.В., Голышев С.В. Программирование. Ступени успешной карьеры. Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. Объектно-ориентированное программирование на PHP. Авторы: Кузнецов М.В., Симдянов И.В. PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум MySQL

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Блокировка?
 
 автор: Настя   (07.09.2005 в 23:24)
 
 

Подскажите, плиз, как тут быть.

Пользователь запускает скрипт, который:
- смотрит в одной таблице mysql последний ID и загружает туда + в другую таблицу некие строки, завязанные на этот ID+1

Проблема в том, что если скрипт запускают несколько пользователей одновременно, то последний ID у них оказывается одинаковым (т.к. ни один из них еще не загрузил новые строки, а только успел считать последний ID). И даже если использовать last_insert_id, как я понимаю, будет то же самое.

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

   
 
 автор: Евгений Петров   (07.09.2005 в 23:28)   письмо автору
 
   для: Настя   (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:49)   письмо автору
 
   для: Настя   (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, записанный данным пользователем?

   
 
 автор: Евгений Петров   (08.09.2005 в 00:01)   письмо автору
 
   для: Настя   (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 таблицу.

   
 
 автор: Loki   (08.09.2005 в 09:58)   письмо автору
 
   для: Настя   (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:15)   письмо автору
 
   для: Настя   (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 (тот, котрый уже прошел следом за его).

   
 
 автор: Евгений Петров   (09.09.2005 в 00:16)   письмо автору
 
   для: Настя   (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:24)   письмо автору
 
   для: Евгений Петров   (09.09.2005 в 00:16)
 

Хотя нет все правильно ч только что проверил.
Запустил скрипт:

<?
  mysql_query
("INSERT INTO tbl(text) VALUES('Строка')");
  
sleep(10);
  echo 
mysql_insert_id();
?>

И за те 10 секунд которые скрипт спит занес в таблицу ещё одну запись и сркипт выдал мне именно тот id который был сгенерирован именно этим скриптом. Т.е. все должно работать проблема (если она есть) не в этом.

   
 
 автор: cheops   (09.09.2005 в 01:30)   письмо автору
 
   для: Настя   (08.09.2005 в 23:41)
 

Не очень понятно в чём проблема last_insert_id () - возвращает счётчик таблицы, операция вставки атомарна, поэтому никаких сбоев не должно быть, если значение last_insert_id используется после, то следует прибегать либо к блокировке таблицы при помощи LOCK TABLES, либо к транзакциям. К сожалению, транзакции в MyISAM не доступны и необходимо использовать InnoDB, которая в несколько раз медленнее таблицы MyISAM.

   
 
 автор: Евгений Петров   (09.09.2005 в 16:54)   письмо автору
 
   для: cheops   (09.09.2005 в 01:30)
 

Т.е. если кто то успеет добавить что нибудь в БД то last_insert_id будет другим?

   
 
 автор: cheops   (09.09.2005 в 19:59)   письмо автору
 
   для: Евгений Петров   (09.09.2005 в 16:54)
 

Хм... А в смысле не успеет?

   
 
 автор: Евгений Петров   (09.09.2005 в 21:17)   письмо автору
 
   для: cheops   (09.09.2005 в 19:59)
 

Ну вот например вставляется запись в таблицу а потом где то извлекается значение mysql_insert_id(). Так вот если в промежутке времени между запросом и вызовом mysql_insert_id() кто нибудь занесет в б.д. еще одно значение, то изменится ли id или нет. Я лично думаю что нет, т.к. опытным путем проверил, что id возвращается именно тот который был сгенерирован последним запросом а ТЕКУЩЕМ скрипте, а не вообще запросом к б.д.

   
 
 автор: Loki   (09.09.2005 в 22:17)   письмо автору
 
   для: Евгений Петров   (09.09.2005 в 21:17)
 

Более того, last_insert_id относится не просто к текущему скрипту, но и к текущему запросу. То есть если выполнить еще какой-то запрос после добавления записи, то last_insert_id уже не вернет значение (читал об этом - сам не пробовал:)

   
 
 автор: cheops   (10.09.2005 в 00:36)   письмо автору
 
   для: Евгений Петров   (09.09.2005 в 21:17)
 

Ну да не изменится... так и не нужно чтобы это значение изменялось, так как оно предназначено для организации связи между таблицами, т.е. если вы вставили значение с AUTO_INCREMENT вы можете его узнать для того, чтобы поместить это значение в качестве вторичного ключа в другую таблицу. Если значение будет "плыть" никакой связи не получится. Так ведь больше и надобности нет - число записей всегда можно узнать при помощи функции count() - ей и следует пользоваться и ничем другим, а новые значения AUTO_INCREMENT - это внутреннее дело базы данных.

   
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования