Witam.
Potrzebuję porady/doradztwa.
Mianowicie tworzę aplikację opartą o mysql działającą na wielu stanowiskach jednocześnie.
Problem polega na tym, że niezbyt mam pomysł jak ugryźć temat odnośnie zapisu danych.
W planach jest takie coś:
Użytkownik loguje się do programu, pobiera najwyższy numer wyceny z bazy i z automatu zaczyna o 1 wyżej tworzyć nową.
Problem w tym, że jeżeli 5 userów zacznie tworzyć wyceny na raz to początkowo każdy z nich będzie miał ten sam numer a chciałbym tego uniknąć.
Może pomożecie jak tego dokonać?
Pozdrawiam
Zrób tak jak np. w Optimie. Jak dodajesz dokument to w polu Numer masz ustawione Auto, a numer jest nadawany dopiero po zapisaniu. Jak potem otwierasz ponownie ten dokument to wtedy wyświetlasz już jego właściwy numer.
Jak @mały pisze. Trigger w bazie danych na insert row. Tabelka z numerami (w latach, miesiącach jak chcesz).
No dobra, ale w momencie kiedy 5 userów otworzy program to wszyscy maja ten sam numer. Problem w tym, że chcę tego uniknąć
To daj im losowe numery
no ale przecież numer dokumentu możesz wyświetlić dopiero po utworzeniu dokumentu w bazie danych. Czy musi być wyświetlany zanim zostanie zapisany w bazie ?
Docelowo mają widzieć numer Od razu
w takim razie proponuję utworzyć tablice z numeracją dokumentów. Po zalogowaniu użytkownika do programu lub rozpoczęciu przez niego wyceny następuje pobranie ostatniego numeru z tabl. numeracji, utworzenie nowego numeru( np. powiększenie o 1 poprzedniego) i zapis do dodatkowej tablicy (pierwszy command) i potem insert wyceny (drugi command) z utworzonym wcześniej numerem.
Właśnie testowałem takie rozwiązanie kiedy 2 userów zapisuje w tym samym momencie i niestety utworzył tylko jeden numer, a towary z dwóch kompów włożył do jednej wyceny
ale to jest ZŁE podejście bo jak ktoś zrezygnuje z zapisu dokumentu a w tym czasie ktoś inny zapisze dokument nowszy to zostanie dziura w numeracji co nie jest dobre (a w niektórych sytuacjach może ściągnąć na głowę skarbówkę).
EDIT @slawek19926 bo pobranie numeru i aktualizację trzeba robić w transakcji blokującej aby nikt inny nie mógł w tym samym momencie pobrać numeru tylko musiał zaczekać
zdaje sobie sprawę , że robią się "dziury" w numeracji ale w niektórych rozwiązaniach to nie przeszkadza. Ewentualnie, po zalogowaniu można wyszukać najniższy numer z "dziury" i zapełnić go w pierwszej kolejności. Oczywiście o ile dopuszczalna jest taka pomieszana numeracja.
abrakadaber napisał(a):
ale to jest ZŁE podejście bo jak ktoś zrezygnuje z zapisu dokumentu a w tym czasie ktoś inny zapisze dokument nowszy to zostanie dziura w numeracji co nie jest dobre (a w niektórych sytuacjach może ściągnąć na głowę skarbówkę).
EDIT @slawek19926 bo pobranie numeru i aktualizację trzeba robić w transakcji blokującej aby nikt inny nie mógł w tym samym momencie pobrać numeru tylko musiał zaczekać
no to jeśli mogą być dziury to co za problem pobierać ten numer z sekwencji (czy co tam ma baza, której używasz)
Dziur niestety nie może być. Klient tego niedopuszcza
to albo dziury w numeracji albo numer nadawany przy zapisie
No właśnie problem w tym, że numer ma być widoczny od razu... Dodatkowo każdy ma mieć możliwość własnej numeracji
Nie ma takiej możliwości...
Nie masz możliwości przewidzenia czy użytkownik dokument zapisze cze nie.
A możesz powiedzieć dlaczego numer musi być widziany już na etapie tworzenia dokumentu?
czyli każdy użytkownik ma mieć własną numerację ? jeśli tak to klucz planujesz zapisać w postaci np. login/...kolejny numer użytkownika ?
slawek19926 napisał(a):
No właśnie problem w tym, że numer ma być widoczny od razu... Dodatkowo każdy ma mieć możliwość własnej numeracji
Po komentarzy @Zwrob pomyślałem że to jednak możliwe.
Jeżeli każdy ma mieć swoją numerację to wystarczy zablokować wielokrotne logowanie jednego użytkownika.
I tu jest kolejny problem ponieważ 1 user załóżmy admin może zalogować z dwóch kompóterów.
slawek19926 napisał(a):
I tu jest kolejny problem ponieważ 1 user załóżmy admin może zalogować z dwóch kompóterów.
W takim razie cofam to co napisałem w ostatnim komentarzu i wracam ze stwierdzeniem że to nie realne :).
I jeszcze raz podpytam: dlaczego musisz znać numer dokumentu już w trakcie jego tworzenia?
Dobra wracamy to możliwości wpuszczenia tylko jednego usera o danym loginie
A może wymagania pozwalają na taką akcję:
Jeśli użytkownik zacznie tworzyć nowy dokument i go nie zapiszę przez jakiś określony czas (np 24h albo i krócej) - to oznaczamy taki rekord jako "Niedokończony" - a po ponownym zalogowaniu user może zechcieć kontynuować pracę nad niedokończonymi dokumentami - to wydaje się mieć jakiś tam sens :D
Dochodzi pytanie czy numeracja musi być zgodna chronologicznie (i czy w ogóle na dokumentach zapisywana jest data ;) ).
Ja w swojej aplikacji rozwiązałem to tak, że przy tworzeniu dokumentu nadawany jest kolejny numer "i" (wstępny i tylko na formularzu, nie w bazie). Podczas zapisu do bazy aplikacja sprawdza, czy numer ten nie został w miedzyczasie zajęty, jeżeli jest wolny to numer pozostaje bez zmian, jeżeli jest już zajęty to wyskakuje info dla użytkownika i nastepuje jego zmiana na "i"+1. Na pole z numerami jest nałożony unikalny indeks więc fizycznie nie ma możliwości utworzenia dwóch rekordów o tym samym numerze. Dziur też nie ma, bo ostateczna weryfikacja nastepuje w momencie zapisu do bazy, więc użytkownik "nie blokuje" wcześniej pozycji w bazie.
Czyli aplikacja pokazuje "przewidywany numer" a nie ten pod którym zostanie zapisany dokument i to jest ok :).
Jednak z tego co zrozumiałem @slawek19926 musi znać ten ostateczny numer już przy tworzeniu dokumentu.
slawek19926 napisał(a):
Dobra wracamy to możliwości wpuszczenia tylko jednego usera o danym loginie
No to wtedy przy tworzeniu pobierasz ostatni numer dokumentu danego użytkownika, zwiększasz o jeden i gotowe :).
@axelbest: coś w rodzaju buforu też ma być...
No i urodził się problem.
Mam zapytanie:
$"{$"ALTER TABLE wyceny ADD INDEX (user_id);
INSERT IGNORE INTO wyceny (user_id) VALUES ((SELECT id FROM uzytkownicy WHERE username = '{klient}'));
SELECT lpad(max(wycena_user+1),"}{MyIni.Read("zera","wyceny")},0) as numer FROM wyceny WHERE user_id = (SELECT id FROM uzytkownicy WHERE username = '{klient}')"
Po każdym uruchomieniu w bazie tworzy mi nowy wiersz :/
Sorki za post wyżej. Niezauważyłem, że nie jestem zalogowany :)
Odnośnie zapytania... Zapytanie miało służyć temu, że jeżeli user nie posiada jeszcze żadnych wycen to wywalało mi błąd, więc zrobiłem tak, że wkłada do bazy iż user posiada wycenę o nr 0 i od tego miejsca liczy.