[ salvaric @ 26.11.2015. 20:40 ] @
Pozdrav,

opet ja sa svojim dilemama i problematikama.

Na koji način da rešim sledeći problem,
naime, pravim client aplikaciju koja koristi jednu MySql bazu podataka na web serveru, ne koristim db komponente, otvorim tabelu->učitam podatke u određenu komponentu->zatvorim tabelum, sad problem sa kojim se susrećem jeste da kad npr. otvorim neku formu za upis novih podataka u bazu, upitom pokupim max(id)+1 (id polje nije autoincrement već ga sam kreiram) i dodelim ga automatski za novi slog, međutim, u koliko drugi client koristi istu formu, tj. koristi unos na istu tabeli i njemu će se dodeliti isti id, tako da prilikom insertovanje će se preslikati ili šta već. Dodatni problem jeste što taj id koristim na datoj formi za još neke druge parametre koji su vezani za taj slog.

U određenom momentu će se desiti da dvije ili više aplikacija u isto vreme vrše upis i potvrdu, tu će nastat havarija, a ne smem zabraniti unos bilo koje.

[Ovu poruku je menjao salvaric dana 26.11.2015. u 21:51 GMT+1]
[ Rapaic Rajko @ 27.11.2015. 07:55 ] @
Ja sam u praksi video neko resenje datog problema (iako je najbolje autoincrement polje).
To je otprilike ovo:

1) Napraviti u samoj bazi generator GetID (neki slican naziv) koji vraca unique ID. U sustini generator samo radi increment nekog podatka i vraca pozivaocu; ono sto je bitno je da je rezultat jedinstven. Koliko se secam, potrebno je da se generator moze resetovati (kao i podesiti da ide od neke vrednosti).
2) Pre bilo kakvog inserta u aplikaciji, pozove se GetID i koristi se dobijeni ID za tekuci insert SQL.
3) Istina je da tako moguce imas 'rupe' (preskoke) sa vrednostima ID u tabelama (recimo ako insert/transakcija pukne, ili dva razlicita SQL inserta rade istovremeno), ali - a) vrednosti ID su uvek rastuce i b) osnovni problem (concurency IDs) je resen.

Pozz
[ captPicard @ 27.11.2015. 09:00 ] @
ID se generira u trenutku kada se radi Commit, na taj način onaj tko prvi Commita - njegova djevojka.

Pročitaj si malo i o temporary tablicama, mogle bi ti biti korisne:

MySQL Temporary tables
[ captPicard @ 27.11.2015. 09:02 ] @
ID se generira u trenutku kada se radi Commit, na taj način onaj tko prvi Commita - njegova djevojka.

Pročitaj si malo i o temporary tablicama, mogle bi ti biti korisne:

MySQL Temporary tables
[ salvaric @ 27.11.2015. 10:52 ] @
Citat:
ID se generira u trenutku kada se radi Commit

Jeste, al meni treba taj id pre commit-a, kad se otvori forma za novi unos npr. partnera, jer taj id dodeljujem i u tabelu tekuci_racuni kao identifikator računa, a postoji velika verovatnoća da će i drugi klient to isto učiniti, tako da će se i njemu dodeliti isti id u koliko prethodni nije završio unos, tj. insert nad tabelom. Query-je ne ostavljam otvorene, pošto koristim server sa neta, da ne bi nastala neka havarija sa podacim, tako da "Temporary Tables" mi nisu u opticaju.
[ savkic @ 15.12.2015. 07:46 ] @
Verovatno sam zakasnio sa odgovorom (nisam ni video ranije pitanje) ali u osnovi imas dva nacina:
a) zatrazis od baze da ti dodeli ID putem generatora ili sequence, to je sigurno jedinstveno i nema ponavljanja (ali ako odustanes od unosa, imaces neiskorisceni ID)
b) radis sve u memoriji i koristis neke privremene vrednosti i tek kada korisnik potvrdi sve, saljes upis u bazu.
[ salvaric @ 15.12.2015. 08:50 ] @
B - varijanta je usvojena, s tim da vršim upis i tražim povratnu informaciju poslednjeg id (LAST_INSERT_ID()) i korigujem ga na drugim slogovima.

Npr. kod unosa novog računa, stavke računa se vezuju za taj id, i sve se kreira u memoriji do samog upisa u bazu, do tad koristim bilo koji id (npr. "0"), i nakon upisa u tabelu računi tražim poslednji id i korigujem ga nad stavkama (promenim vrednost "0" na poslednji id), i nakon toga ide i upis stavki u bazu.

Možda nije jednostavno, al funkcioniše kako treba, za sad.
[ ((BugA)) @ 15.12.2015. 21:57 ] @
Cek, cek, trazis poslednji trenutni ID tabele? Sta ako dva klijenta zatraze to istovremeno, hoce li dobiti isti broj? Ne mora ni da bude bas istovremeno, bitno je da drugi zatrazi nakon prvog, a pre no sto prvi izvrsi upis.
[ salvaric @ 15.12.2015. 22:06 ] @
Ima baš ta rupa, ali je vrlo mala verovatnoća da se to desi.

Upiti se izvršavaju za redom, id računa je sam stavio da bude autoincrement, to sam zaboravio navesti, i nakon upisa računa sledi upit last id-a i upis istaog na stavkama i upis stavki.

insert into tab_racuni ...
select LAST_INSERT_ID()
insert into tab_racuni_stavke ...

ako postoji neka malo bolja ideja, voleo bih čuti.
[ captPicard @ 15.12.2015. 22:15 ] @
Nije ti to dobro. Ako sam te dobro shvatio, ti zapišeš ID u tabelu računi i nakon toga pitaš LAST_ID da bi zapisao taj ID u stavke. Ako ti uleti netko sa novim ID-em u tabelu računi dok ti još nisi zapisao tabelu stavke, dogodit će ti se havarija.

Uzmi max(id) prije nego bilo šta zapišeš, prepiši taj ID na tabelu računi i na tabelu stavke i onda možeš "commitat". Nije niti to 100%, ali pošto radiš kako si naveo, barem se ne može dogoditi havarija. I onda ako dobiješ grešku "violation of PK" znači da je netko uletio prije tebe, traži novi ID i opet sve zapiši.

Malo sam nabzinu napisao, ali nadam se da si shvatio.
[ salvaric @ 15.12.2015. 22:53 ] @
Testirao sam, u koliko je u pitanju autoincrement polje i bez commita Query snima slog i dodeljuje mu auto id, a drugom korisniku dodeljuje sledeći tako da nema šanse da dođe do sukoba.

posle prvog inserta stavio sam breakpoint i stopirao dalji niz operacija pre commita i pre upisa stavki, i pokrenuo novu aplikaciju i išao na novi upis i snimanje, i preskočio je taj id, tako da radi kako treba ovo kako sam naveo.
[ ((BugA)) @ 15.12.2015. 23:24 ] @
Da, ako je auto-increment, upis ce ti raditi kako treba, ali LAST_INSERT_ID() i dalje ne deluje dobro. Sta se desava u sledecoj situaciji:

- klijent 1, insert into tab_racuni
- klijent 2, insert into tab_racuni
- klijent 1, select LAST_INSERT_ID() << da li ovde klijent sada i dalje dobija poslednji ID - koji ce biti pogresan, jer pripada drugom klijentu
- klijent 1, insert into tab_racuni_stavke << upis pogresnog ID-a...
[ salvaric @ 16.12.2015. 00:01 ] @
Ne, to sam i proveravao, pošto se select radi pre commita, last insert id uzima vrednost od tog clienta, a ne od poslednjeg insertovanog iz drugog klienta. Izgleda da ta autoincrement polja se sama automatski čuvaju i bez commita, tj.rezervišu.
[ salvaric @ 16.12.2015. 07:59 ] @
I ja sam imao tu dilemu, al sve je ok.

"select LAST_INSERT_ID()" uzima "id" do momenta konektovanja na mysql bazu ili poslednji insertovan u toku konekcije, posle iako neki drugi client vrši upis (insert) , upit će dati stari id a ne novi od client-a, a clientu će dodeliti novi, kao što kod mysql baze, a ne znam da li je i kod drugih tako, ako neko drugi izvrši novi unos ili korekciju, sa "select * tabela..." neće prikazati te izmene sve dok se konekcija ne refresh-uje, tj. disconnect->connect.

Verovatno da sam posle prvog inserta radio disconnect pa connect nad bazom, došlo bi do tog problema.
[ Rapaic Rajko @ 16.12.2015. 09:11 ] @
Ja mislim da ovo gore radi zbog transakcije (pominjes commit).
Transakcija bukvalno pravi 'presek stanja' baze za klijenta koji je koristi; zato i funkcionise LAST_INSERT_ID.

Pozz