Mysql быстро создать новое имя

Discussion in 'PHP' started by Apeckou, 3 Jul 2012.

  1. Apeckou

    Apeckou Elder - Старейшина

    Joined:
    23 Jan 2007
    Messages:
    143
    Likes Received:
    11
    Reputations:
    0
    Здравствуйте, у меня возникла проблема, и я чето не знаю как ее решить. Дело в том, что на моем сайте (файлообменник) при загрузке нового файла выбирается специальное имя чтобы его сохранить.

    Делается это следующим образом:

    есть таблица с инфой о файлах, в ней
    Code:
    fid not null auto_increment primary key,
    nname varchar (50)
    ....
    .....
    прочая инфа
    ....
    ....
    
    При начале загрузки нового файла, выбирается максимальное значение fid, и _сразу же_ создается новая запись где fid автоинкремент, а nname=максимальный до этого fid+1.
    далее идут всякие вычисления, которые занимают много времени, а потом созданная в таблице запись просто UPDATEится, зная какое nname выбрано.
    Немного путанно объяснил, код кусок кода:

    Code:
    //смотрим сколько файлов и выбираем их количество для создания имени
    $stmt=$link->prepare("SELECT fid+1 FROM MYFILES ORDER BY fid DESC LIMIT 1");
    $stmt->bind_result($newcount);
    $stmt->execute();
    $stmt->fetch();
    $stmt->close();
    
    $prestatus='prepare';
    //сразу забиваем имя под новый файл с пустой инфой и статусом "deleted"
    $stmt=$link->prepare("INSERT INTO MYFILES(nname,status) VALUES(?,?)");
    $stmt->bind_param("ss", $newcount,$prestatus);
    $stmt->execute();
    $stmt->close();
    
    echo("Место под файл занято: $newcount");
    
    
    ..........
    ..........
    тут всякие вычисления, об их скорости можно не заботиться, т.к. место уже "забито"
    ..........
    ..........
    
    
    //если все удачно прошло - дописываем инфу в забитую ячейку
    $status='normal';
    $stmt=$link->prepare("UPDATE MYFILES SET всякиезначения=?,.....................,status=? WHERE (nname=?)");
    $stmt->bind_param("......",........,$status,$nname);
    $stmt->execute();
    $stmt->close();
    
    Казалось бы, все сделано качественно.
    Но седня сканил акуниксом, так он мне файлы быстро-быстро грузил...и потом я заметил несколько записей в БД с разными FID но одинаковыми NNAME
    Вообще не понял как такое могло быть и как от этого избавляться. Разве что еще короче написать первые два запроса (найти и забить новые значения).
    Но этош пипец....
    Короче я расстроен... посоветуйте ченить, может я что-то не замечаю (сонный уже, 4 утра)? оО
     
  2. Gifts

    Gifts Green member

    Joined:
    25 Apr 2008
    Messages:
    2,494
    Likes Received:
    807
    Reputations:
    614
    Apeckou Да, возможен race condition между
    PHP:
    $stmt=$link->prepare("SELECT fid+1 FROM MYFILES ORDER BY fid DESC LIMIT 1"); 
    //и
    $stmt=$link->prepare("INSERT INTO MYFILES(nname,status) VALUES(?,?)");
    Правильно делать так:
    PHP:
    $stmt=$link->prepare("INSERT INTO MYFILES(nname,status) VALUES(?,?)");
    $stmt->bind_param("ss"$newcount,$prestatus);
    $stmt->execute();
    $fid $stmt->insert_id// Здесь будет fid новой записи.
    $stmt->close();
    Плюс
    PHP:
    $stmt=$link->prepare("UPDATE MYFILES SET всякиезначения=?,.....................,status=? WHERE (nname=?)");
    $stmt->bind_param("......",........,$status,$nname);
    Следует заменить на
    PHP:
    $stmt=$link->prepare("UPDATE MYFILES SET всякиезначения=?,.....................,status=? WHERE (fid=?)");
    $stmt->bind_param("......",........,$status,$fid);
    База гарантирует только уникальность fid, а не уникальность nname (если только вы не повесили уникальный индекс на столбец).
     
    _________________________
    1 person likes this.
  3. Apeckou

    Apeckou Elder - Старейшина

    Joined:
    23 Jan 2007
    Messages:
    143
    Likes Received:
    11
    Reputations:
    0
    Крутяк, добавил плюсиков скока мог, завтра буду переделывать!)
    я вот щас сижу и думаю, нафига я вообще этот nname ввел.. щас уже не помню, но чето он мне перестал нравиться резко
    а переделывать слишком много всего, чтобы от него избавиться(