alter procedure sp_nova_ponuda ( @idKorisnika int, @idAukcije int, @iznosPonude decimal(8,2) ) as begin begin try set transaction isolation level serializable begin tran declare @maxIznos decimal(8,2) select top 1 @maxIznos=iznosPonude from ponude where idAukcije = @idAukcije order by vremePonude desc declare @status varchar(10), @pocetnaCena decimal(8,2) select @status=status, @pocetnaCena=pocetnaCena from aukcije where id = @idAukcije if (@status = 'otvorena') begin if (@maxIznos is null and @iznosPonude >= @pocetnaCena) or --prva ponuda (@maxIznos is not null and @iznosPonude > @maxIznos) insert into ponude(idKupca, idAukcije, iznosPonude, vremePonude, statusPonude) values(@idKorisnika, @idAukcije, @iznosPonude, getdate(), 'prihvacena') else print 'Vasa ponuda nije veca od aktuelne.' end else print 'Aukcija je zatvorena.' commit tran end try begin catch rollback tran print 'Vasa ponuda nije prihvacena, pokusajte ponovo.' end catch end go /* Ako jedan poziv procedure sp_nova_ponuda procita trenutni maksimalni iznos, a zatim drugi poziv procita isti taj iznos i unese vecu ponudu maksimalna cena se promenila, ali prvi poziv to ne vidi, pa moze da se desi da nakon toga prvi poziv unese ponudu koja je veca od prethodne maksimalne, ali manja od ponude koju je malopre dao drugi poziv i onda ce manja ponuda biti prihvacena i posmatrace se kao aktuelna jer je najkasnija. Resenje je serializable koje ce spreciti insert nove ponude ako je bilo sta iz tabele ponude procitano. Serializable moze dovesti do deadlock-a. */ exec sp_nova_ponuda 5, 2, 1400 exec sp_nova_ponuda 3, 2, 1700 exec sp_nova_ponuda 1, 3, 4900 exec sp_nova_ponuda 2, 3, 5200 exec sp_nova_ponuda 2, 1, 7700 go alter database e_aukcija set allow_snapshot_isolation on go alter procedure sp_aktuelna_ponuda ( @idAukcije int ) as begin begin try set transaction isolation level snapshot begin tran declare @aktuelnaPonuda decimal(8,2) declare @pocetnaCena decimal(8,2) declare @status varchar(10) select top 1 @aktuelnaPonuda=iznosPonude from ponude where idAukcije = @idAukcije order by vremePonude desc select @pocetnaCena=pocetnaCena, @status=status from aukcije where id = @idAukcije if @status='zatvorena' print 'Aukcija je zatvorena!' else if @aktuelnaPonuda is null begin print 'Uputi prvu ponudu!' set @aktuelnaPonuda = @pocetnaCena end print 'Aktuelna ponuda: ' + convert(varchar(11), @aktuelnaPonuda) commit tran end try begin catch rollback tran print 'Doslo je do problema, pokusajte ponovo.' end catch end go /* snapshot Ako procitamo trenutnu najbolju ponudu, a ta ponuda je upisana ali ne i commit-ovana, i onda se ta ponuda rollback-uje, doslo je do prljavog citanja i mi korisniku prikazujemo ponudu koja zapravo nije upisana u bazu. Read committed i snapshot ce procitati commit-ovane podatke. Read committed transakcija moze da se blokira dok ceka commit-ovanje podataka. Snapshot transakcija se nece blokirati, vec ce prikazati stanje onakvo kakvo je bilo kad je transakcija zapocela. RC daje svezije podatke, ali ima blokiranja. Snapshot daje starije podatke, ali nema blokiranje. Zadatak kaze da je prioritet da ima sto manje blokiranja, zato uzimamo snapshot kao resenje. */ /* Ovde eventualno moze da se desi da procitamo aktuelnu ponudu, pa da neko drugi upise novu ponudu i onda da se zatvori aukcija, i mi onda procitamo da je aukcija zatvorena i prikazemo staru ponudu kao poslednju ponudu. Snapshot nema ovaj problem, pa je i zbog ovoga bolji izbor od read committed. */ alter procedure sp_sve_prihvacene_ponude ( @idAukcije int ) as begin begin try set transaction isolation level snapshot begin tran select k.username, p.iznosPonude, p.vremePonude from ponude p join korisnici k on k.id = p.idKupca where p.idAukcije = @idAukcije order by p.vremePonude desc commit tran end try begin catch rollback tran print 'Doslo je do problema, pokusajte ponovo.' end catch end go /* Ovde imamo jedan veliki select, pa je najbolje staviti snapshot. Bitno je da se ne citaju ponude koje jos nisu committ-ovane. Kao i u prethodnoj proceduri, snapshot bi radio brze, a read committed bi dao svezije podatke. */ exec sp_sve_prihvacene_ponude 1 go alter procedure sp_zatvaranje ( @idAukcije int ) as begin begin try set transaction isolation level read uncommitted begin tran update aukcije set status = 'zatvorena' where id = @idAukcije declare @idPonude int select top 1 @idPonude=id from ponude where idAukcije = @idAukcije order by vremePonude desc update ponude set statusPonude='pobednik' where id = @idPonude commit tran end try begin catch rollback tran print 'Doslo je do problema, pokusajte ponovo.' end catch end go /* Ako sam ja krenuo da zatvaram, niko nece moci da ubaci novu ponudu. Ako se trenutno ubacuje nova ponuda, necu moci da zatvorim, dok se ona ne ubaci. Ne moze doci do anomalije, svejedno je koji nivo izolacije stavimo, moze cak i read uncommitted i nece doci do nekonzitentnosti. */ exec sp_zatvaranje 1 exec sp_zatvaranje 2 go alter procedure sp_naplata ( @idKlijenta int, @idAukcije int ) as begin begin try set transaction isolation level repeatable read begin tran declare @iznosNaRacunu decimal(8,2) select @iznosNaRacunu=iznosNaRacunu from korisnici where id=@idKlijenta declare @statusAukcije varchar(10) select @statusAukcije=status from aukcije where id=@idAukcije declare @iznosPonude decimal(8,2) declare @kupacPobednik int select @iznosPonude=iznosPonude, @kupacPobednik=idKupca from ponude where idAukcije = @idAukcije and statusPonude = 'pobednik' if @statusAukcije='zatvorena' and @kupacPobednik=@idKlijenta and @iznosPonude <= @iznosNaRacunu begin update korisnici set iznosNaRacunu = iznosNaRacunu - @iznosPonude where id = @kupacPobednik update aukcije set status = 'naplacena' where id=@idAukcije end else begin print 'Doslo je do greske' end commit tran end try begin catch rollback tran print 'Doslo je do problema, pokusajte ponovo.' end catch end go /* Moze da se desi da se istovremeno pokrenu dve naplate za istog klijenta, ali za razlicite aukcije. Oba poziva procitaju da klijent ima dovoljno para i naplate mu aukciju, ali klijent zapravo nema dovoljno para za obe aukcije zbirno. Sa repeatable read, jednom kada se iznos procita, on ne moze da se menja do kraja transakcije. Ako se pokusaju obe naplate istovremeno, doci ce do deadlock-a i jedna ce se ponistiti. */