[ itf @ 25.11.2008. 13:49 ] @
U C++u koristim stored proceduru za update podataka na SQL server. Ona izgleda ovako:

Code:
USE [Pokus]
GO
/****** Object:  StoredProcedure [dbo].[MojUpdate]    Script Date: 11/25/2008 14:18:59 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROC [dbo].[MojUpdate] @primaryKey int,@Ime  nvarchar(50), @Prezime nvarchar(50),@Godine int 
AS 
BEGIN TRAN 
UPDATE Osoba WITH (ROWLOCK) SET Ime = @Ime  WHERE ID = @primaryKey
IF @@ERROR != 0 
BEGIN 
GOTO ERRORHANDLER  
END 

UPDATE Osoba WITH (ROWLOCK) SET Prezime= @Prezime  WHERE ID = @primaryKey
IF @@ERROR != 0 
BEGIN 
GOTO ERRORHANDLER  
END 

UPDATE Osoba WITH (ROWLOCK) SET Godine= @Godine  WHERE ID = @primaryKey  
IF @@ERROR != 0 
BEGIN 
GOTO ERRORHANDLER  
END 

COMMIT TRAN
select* from dbo.Osoba
RETURN 

ERRORHANDLER: 
ROLLBACK TRAN  /* ponistavas promjene koje si napravio ako ti neki od update-a ne prodje */
RAISERROR ('Ne bi išlo....',16,1)  /* ova linija baca exception sa porukom u tvom programu */
select* from dbo.Osoba


U aplikaciji pozovem tu proceduru zajedno sa svim parametrima i ona uredno izvrši update željenog stupca. Međutim, kada dvojica klijenata istovremeno updajte-aju isti zapis uopće mi se ne detektira data concurrency. Točnije, svima se izmjene prihvate bez da su vidjeli zadnje stvarno stanje zapisa. Jednostavno, samo prepisuju jedan preko drugog.

Ono što bi ja htio jest da mi netko opiše kako da ovu proceduru proširim tako da nakon što dodam @timestamp da mogu provjeriti timestamp u vrijeme update-a te prema tome detektirati da li je bilo izmjena. Kako da to isprogramiram u stored proceduri?

Isto tako, kako da u stored proceduri provjerim da zapis u međuvremenu nije izbrisan?

Hvala
[ sallle @ 27.11.2008. 11:43 ] @
1. cini mi se da se stored procedure same po sebi izvrsavaju u transakciji.
To znaci otprilike da ti nemas konkurentni pristup, nego sekvencijalan od strane klijenata.

u toj tabeli gde treba da pratis da li je neko menjao od tvog zadnjeg citanja uvedi i polje timestamp.
Procedura nek ti ima jos jedan ulazni parametar @clientTimestamp.

Eo otprilike skica :
Code:

select @trenutniStamp = select timestamp from tabela where id = @primarykey

if (@trenutniStamp is null)
then 
 --izbrisan red, digni neki error - mozes i u aplikaciju izbacis error ako postavis severity level 11 cini mi se
else
begin
  -- red postoji
    if (@trenutniStamp<>@clientTimestamp)
    --raisuj error (podaci kod klienta su dirty)
    else 
    --sve ok, izvrsi te update-ove koje imas
end


[ itf @ 27.11.2008. 12:31 ] @
E hvala. Budem pokušao.
[ itf @ 29.11.2008. 15:31 ] @
I još jedno pitanje.. koliko je timestamp precizan tj. siguran? Koje vrijeme on točno mjeri?
[ mmix @ 01.12.2008. 11:07 ] @
trenutno je po sadrzaju timestamp=rowversion=binary(8)=bigint counter zadnjeg update-a bilo koje timestamp tabele NA CELOM SQL SERVERU ali ce to biti promenjeno pre ili kasnije, ono sto ce ostati je da su dva timestampa uporediva (veci stamp = noviji update). Isto tako bi trebao da koristis rowversion umesto timestamp posto ce timestamp biti promenjen da sadrzi datetime zadnjeg update-a reda, dok ce rowversion zadrzati funkcionalnost koju sad ima timestamp.
[ itf @ 01.12.2008. 11:43 ] @
Ali opet, zanima me koja preciznost je svega toga u timestamp-u? Milisekunde, mikrosekunde?

A taj rowversion nemam nigdje ponuđenog...
[ mmix @ 01.12.2008. 12:13 ] @
Nisi me razumeo, ne postoji preciznost u timestampu trenutno jer trenutno timestamp NIJE po SQL92 standardu i ne sadrzi datetime, trenutno timestamp sadrzi trenutnu vrednost globalnog brojaca insert/update komandi koje su se desile nad tabelama sa timestamp/rowversion poljima na nivou celog servera. Ta vrednost nema nikakve veze sa vremenom i datumima vec samo sa brojem oepracija koje su se desile u medjuvremenu (npr ako je tvoj timestamp 1022 a desilo se 25 update-a na tamo nekim bazama i tabelama sledeci update na tvom redu ce promeniti timestamp u 1022+25+1 = 1048 )

A rowversion ne vidis zato sto radis iz table dizajnera. Ako uradis ovo radice:

Code:

ALTER TABLE dbo.MojaTabela ADD verzija rowversion NOT NULL




[ itf @ 01.12.2008. 12:18 ] @
EDIT:
Sad sam izvršio gornji SQL upit u stored proceduri pa mi je javio da već imam polje timestamp, a kad ga iz tablice maknem onda ga ovaj kod gore opet doda. Znači, ništa mi zapravo nije promjenio jer i dalje koristi timestamp...

[Ovu poruku je menjao itf dana 01.12.2008. u 13:37 GMT+1]
[ mmix @ 01.12.2008. 12:38 ] @
ne zna se jos tacno dal ce biti greske ili nece, generalno mislim da se zbog toga i zentaju da promene, ali da bi se uskladili sa SQL92 timestamp mora da prestane da bude tip za sebe i da postane sinonim za datetime tip sa automatskim updateom. Kakve bi to posledice imalo zavisi od koda koji radi sa tim podacima. Automatski upgrade baza ce verovatno prebaciti sva timestamp polja da budu rowversion da bi zadrzali kompatibilnost, ali sve skripte koje budu koristile timestamp kreirace datetime polje.


A inace, proveravas kao sto ti je salle naveo. Ti ucitas postojeci timestamp/rowversion i cuvas ga offline dok korisnik menja podatke, onda kad posaljes podatke u stored proceduru saljes i stari timestamp. Ako taj timestamp vise ne postoji u tabeli znaci da je obrisan a ako je za isti kljuc u tabeli drugaciji timestamp (bice uvek veci osim ako tokom izmene podataka admin nije uradio restore neke stare baze) onda znas da je neko drugi promenio u medjuvremenu i radis neki fallback (vracas gresku ili ponovo ucitas nove podatke i vratis korisniku, itd, itd). To se zove passive concurrency.


Citat:
Sad sam izvršio gornji SQL upit u stored proceduri pa mi je javio da već imam polje timestamp, a kad ga iz tablice maknem onda ga ovaj kod gore opet doda. Znači, ništa mi zapravo nije promjenio jer i dalje koristi timestamp...


TO je zato sto je trenutno rowversion sinonim za datetime. U creation SQL skriptama treba da drzis rowversion bez obzira na to sto se trenutno kreira timestamp.

PS: Nemoj brisati delove poruka jer tema gubi na kontinuitetu.
[ itf @ 01.12.2008. 12:52 ] @
Ok. Zahvaljujem na odgovorima.