Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[PHP / MySQL] Dodawanie rekordów, a ID dodawanego rekordu

09 Sty 2011 19:28 6403 13
  • Poziom 18  
    Witam

    Od jakiegoś czasu borykam się z problemem wytargania z bazy ID dodawanego rekordu.
    ID jest to piramy key, więc jest to autoincrement.
    zasadniczo robię to przez:
    Kod: sql
    Zaloguj się, aby zobaczyć kod

    ale jakoś nie podoba mi sięto rozwiązanie.
    Przykład:
    tabela 1:
    Kod: sql
    Zaloguj się, aby zobaczyć kod

    i teraz
    w tabela1 mam dane z który potrzebuję ID wytargać do tabela2 jak coś dodaję
    dla przykładu:

    Kod: sql
    Zaloguj się, aby zobaczyć kod

    zawsze jest tak, że najpierw dodaję do 1 tabeli info ogólne z ID które jest generowane automatem, natomiast drugie zapytanie dodaje info szczegółowe do drugiej tabeli, lecz potrzebne jest ID z pierwszej.
    takie rozwiązanie jak wydumałem realizowane przez SELECT MAX(`ID`) [...] owszem działa, puki co bezbłędnie, nie mniej jednak mam wrażenie że przy większej liczbie dodawanych danych, a w sumie gdy zbiegną się dwa wstawiania prawie w tym samym czasie, po prostu pomyli się ID z tabeli 1.
    zapytanie realizuje PHP przez dwa mysql_query();

    ma ktoś jakiś pomysł jak wytargać ID dodawanego rekordu?
    z tego co czytałem na php.net mysql_query nie zwraca takowego wyniku :/
    jakieś pomysły?

    Proszę pamiętać o używaniu znaczników code. - arnoldziq
  • Poziom 18  
    no tak tak tylko że to zwraca ID ostatniego INSERTA, podobnie jak mój wynalazek :/
    Jak pisza:
    Cytat:
    Because mysql_insert_id() acts on the last performed query, be sure to call mysql_insert_id() immediately after the query that generates the value.


    więc wychodzi na to że albo muszę dodać jaką zmienną np. data+czas zapisywana w bazie którą dodam do WHERE przy wyciąganiu ID :/

    no chyba że ktoś ma lepszy pomysł
  • Poziom 18  
    Przede wszystkim chodzi mi o to żeby działało pewnie, a wydaje mi się że zarówno w jednym jak i w drugim przypadku, jeżeli INSERT-y nastąpią praktycznie jednocześnie to ID zostanie odczytane tylko jednego i tego samego w obu przypadkach ;/
    Naturalnie przy moim obciążeniu bazy taka sytuacja jest prawie nie możliwa, ale to jest tylko prawie, a nie zupełnie nie możliwa :/
  • Pomocny post
    Poziom 40  
    mr_grabarz napisał:
    Przede wszystkim chodzi mi o to żeby działało pewnie, a wydaje mi się że zarówno w jednym jak i w drugim przypadku, jeżeli INSERT-y nastąpią praktycznie jednocześnie to ID zostanie odczytane tylko jednego i tego samego w obu przypadkach ;/

    Wydaje Ci się ;)
    Twoje rozwiązanie jest niepewne, ponieważ pomiędzy instrukcjami:
    Kod: sql
    Zaloguj się, aby zobaczyć kod

    a
    Kod: sql
    Zaloguj się, aby zobaczyć kod
    inny klient korzystający w tym samym czasie z bazy może wprowadzić swój rekord, a Ty w drugim zapytaniu odczytasz jego wartość.
    Sytuacja mało prawdopodobna przy małym obciążeniu, rośnie przy większym.

    Natomiast rozwiązanie które Ci zaproponowano ma jedną zasadniczą przewagę:
    Code:
    The value of mysql_insert_id() is affected only by statements issued within the current client connection. It is not affected by statements issued by other clients. 
    . tutaj
  • Poziom 26  
    Ja w takich przypadkach rezygnuję z auto_increment i sam nadaję nowe ID. Wtedy mam pewność że w obu tabelach ID będzie takie samo. Robiąc to wszystko w transakcji mamy pewność poprawnego zadziałania.
  • Moderator Programowanie
    A dlaczego nie wygenerujesz numeru ID, za pomocą procedury i generatora, i po prostu nie użyjesz tego ID ?
    Wartość generatorów jest widoczna dla wszystkich klientów, niezależnie od sesji. Więc problem "podkradzenia" wolnego ID odpada.
  • Poziom 18  
    Dlaczego nie wygeneruje?
    hmm ot choćby dlatego że dostęp do bazy realizowany jest nie tylko via WWW(PHP), ale również przez klienta w formie programu,
    a co za tym idzie na mój prosty rozum musiał bym dalej gdzieś przechowywać to ostatnie wygenerowane ID, najprościej w bazie, a więc chyba prostsze jest jednak jego odczytanie z kolumny która ma autoincrement.

    po testuje to mysql_inser_id
    nie miałem pojęcia że coś takiego istnieje

    dziękuję za pomoc i doradztwo ;)
  • Moderator Programowanie
    Z tym : "najprostsze" to bym się pokłócił.
    Ale każdy ma swoje metody.
    Ja, osobiście, mam bazy do który równoczesny dostęp ma od 20 do 300 osób, poprzez aplikacje klienckie.
    Większość indeksów bazy jest oparta na unikalnych ID. Osobiście jestem zwolennikiem generatorów i generowania numerów ID przez procedury. Ta metoda nigdy mnie jeszcze nie zawiodła. Tym bardziej, że najczęściej, wygenerowane ID trafia nie tylko do jednej, głównej, tabeli, ale jest także aktualizowane w kilku innych.Na dzień dzisiejszy, mam w bazie 84 generatory i wszystko działa, tak jak powinno.
    Ale to tylko jedno z rozwiązań. Jeżeli kolega uważa, że złe lub niewygodne, to trudno.
    BTW: Ma kolega rację, ostatnio wygenerowane ID przechowuję w kodzie programu. I generuję je w momencie zapisu danych do bazy (na chwilę przed). Zapisanie gdzieś w bazie wygenerowanego ID... jest ogólnie mówiąc "trochę nie tego" :) czemu nie przechowa kolega tego ID w kodzie ?
  • Poziom 18  
    marcinj12 napisał:
    inny klient korzystający w tym samym czasie z bazy może wprowadzić swój rekord, a Ty w drugim zapytaniu odczytasz jego wartość.
    Sytuacja mało prawdopodobna przy małym obciążeniu, rośnie przy większym.


    Jakim cudem? Przecież po to się tworzy osobne połączenia dla każdego żądania przez:

    Kod: php
    Zaloguj się, aby zobaczyć kod
  • Poziom 42  
    makkak - jeśli będziemy operować na nietransakcyjnym silniku, jakim jest np MyISAM, to ta uwaga w kontekście przedstawionego zapytania może okazać się słuszna! (choć z małym prawdopodobieństwem). Zaś w przypadku transakcyjnych... Ten kod w ogóle by nie zadziałał poprawnie! ;) Dlatego marcinj12 ma rację. Czyli insert z podselectem na MAX+1 sprawdzi się, ale:
    1. Jeśli pracujemy na nietransakcyjnej bazie
    2. Nie chcemy znać ID (bo go nie będziemy w stanie pobrać).

    Z kolei próba pobrania wcześniej ID będzie miało ten sam efekt, jak praca z transakcjami. BTW - połączenia nie mają nic do rzeczy.

    I dlatego właśnie powinno się stosować metodę z mysql(i)_insert_id! Jest ona w 100% pewna dla każdego z połączeń, tak samo, jak pewne są generatory.
  • Poziom 18  
    @arnoldziq
    dlaczego nie wygeneruje i nie oprę się na procedurze? ano sprawa jest banalnie prosta, nie miałem z nimi nigdy doświadczenia, w sensie generowania ID i mówiąc krótko puki cobie tego nie oczytam i nie po testuje wolał bym nie sprawdzać działania generatora że się tak wyrażę na "żywym organie"
    mówiąc krótko jestem jeszcze za cienki w te klocki ;)

    jak już powiedziałem po testuję po czym wdrożę mysql_insert_id, zobaczymy jaki będzie efekt
  • Poziom 18  
    Ale nie rozumiem tego co Wy piszecie. Skoro mamy pole AUTO_INCREMENT to przecież podczas zapytania INSERT baza wybiera W DANYM POŁĄCZENIU nowe id i w danym połączeniu zapytanie mysql_insert_id zwróci uzyskaną nową wartość. Kombinujecie z jakimiś dziwnymi funkcjami nie wiadomo po co.

    Cytat z dokumentacji MySQL:

    "The value of mysql_insert_id() is affected only by statements issued within the current client connection. It is not affected by statements issued by other clients."

    google translator:

    "Wartość mysql_insert_id () wpływ ma jedynie oświadczenia wydane w ciągu bieżącego połączenia klienta. To nie ma wpływu na sprawozdania wydane przez innych klientów."

    Dokumentacja MySQL - funkcja mysql_insert_id()

    Dodano po 4 [minuty]:

    Dżyszla napisał:
    makkak - jeśli będziemy operować na nietransakcyjnym silniku, jakim jest np MyISAM, to ta uwaga w kontekście przedstawionego zapytania może okazać się słuszna! (choć z małym prawdopodobieństwem). Zaś w przypadku transakcyjnych... Ten kod w ogóle by nie zadziałał poprawnie! ;) Dlatego marcinj12 ma rację. Czyli insert z podselectem na MAX+1 sprawdzi się, ale:
    1. Jeśli pracujemy na nietransakcyjnej bazie
    2. Nie chcemy znać ID (bo go nie będziemy w stanie pobrać).


    Ale przecież w momencie pobierania podzapytaniem MAX+1 może się wykonać inne dodanie rekordu które zmieni tę wartość zanim my ją przypiszemy. Nie lepiej polegac na funkcji która spełnia dokładnie zadanie jakie potrzebujemy wykonać? ;)

    No i co ma wspólnego z tym transakcja? Przecież z definicji transakcje są atomowe i spójne. Poza tym możemy zablokować tabelę do zapisu na czas trwania transakcji.