20. november 2006 - 22:24Der er
6 kommentarer og 2 løsninger
Transactions - men uden at låse tabeller!
Jeg har lavet et website hvor brugere kan købe fiktive ting af hinanden.
Der er nu opstået det problem, at nogle kreative brugere har fundet ud af, at hvis du trykker på "Køb" lynhurtigt efter hinanden - så kan de snyde sig til mange fiktive penge.
Mit "køb-script" ser sådan ud i pseudokode: // tjek om tilbudet findes // hvis tilbud findes { // slet tilbud (så man ikke kan foretage samme køb igen) // træk penge fra sælger // tilføj penge til køber // afslut handel }
PRoblemet er, at hvis dette script eksekveres MEGET MEGET tæt på samme tidspunkt, så vil tilbudet ikke blive slettet før "tjek om tilbudet findes" køres 2. gang (af en sideløbende proces fordi brugeren klikker hurtigt på samme link mange gange).
Jeg ville jo klart kunne løse problemet med transactions - men jeg er ikke interesseret i at låse mine tabeller. Det vil få mit site til at gå alt for langsomt.
Hvordan kan man ellers gøre?
Mit løsningsforslag ville være, at i stedet for foretage "købsprocessen" når brugeren klikker på et tilbud (med tjek om tilbud findes, træk penge, tilføj penge, afslut handel osv.) - så vil der blive oprette en record om, at brugeren gerne vil benytte sig af det købstilbud. Den record vil blive læst af et cronjobs som kører ofte. På den måde vil der aldrig blive oprettet to simultane kørsler af et "køb-script".
Kan du se en bedre løsning end den jeg forslår ovenfor?
Jeg går ud fra du mener at brugerne kan snyde sig til mange fiktive penge ved "sælg"?
Du kan sætte et timestamp på hver handel og så lave således det ikke er muligt for samme bruger at købe/sælge samme vare til/af samme person i et bestemt tidsrum, f.eks. 1 minut.
Du kan deaktivere knappen de trykker på med noget java-halløj (ikke speciel sikker, men som en "ekstra-ting" kunne den være okay.
Hvis du bruger sessions, kan du sikkert lave en kontrol af om de har lavet mere end én handel inden for få sekunder.
Det med timestamp går ikke - forestil dig hvis købs-/salgsprocessen bliver aktiveret 2 gange på NÆSTEN samme tid. Så vil det tjek, der ser om brugeren har handlet inden for det sidste minut ske FØR brugertabellen bliver opdateret med "sidste_handel = NOW()". Derfor nytter det ikke noget.
Ja, jeg kunne deaktivere knappen med JS- men så er det et spørgsmål om tid inden nogen finder ud af kalde url'en direkte via browseren adresse-linje.
Det med sessions - det tror jeg muligvis vil virke :P Jeg tester det lige og vender tilbage... :)
jeg mener at du bør bruge transactions - de er beregnet til det og performance bør ikke forringes så meget (ihvertfald ikke hvis du allerede bruger InnoDB tabeller)
Jeg forsøgte mig via php at kontrollere det med sessions - det viste sig til min overraskelse ikke at være sikkert nok. Der var simpelthen en eller anden form for "forsinkelse" på hvornår session'en blev "synlig" for de andre simultane processor.
Men arnes måde at gøre tingene på (det sidst-nævnte) er da idiotsikker vil jeg umiddelbart sige. I uhyre sjældne tilfælde kan processen stoppes efter pengene er trukket fra sælger og efter pengene er tilføjet til køber, hvilket jo kunne fixes ved at bruge transactions. Men det er for voldsomt i "første omgang".
Jeg har nu sat en if(mysql_affected_rows() == 0) ind for at teste hvorvidt tilbudet findes... det er jeg ret overbevist om i det mindste forhindrer snyd.
Tak for begge jeres svar. I fortjener vidst begge point - så smid et svar :o)
Ups, ovenstående fik jeg vidst skrevet for hurtigt. Der skulle naturligvis stå "EFTER pengene er trukket fra køber og FØR pengene er tilføjet til sælger" :-)
Og skal jeg vidst snart lære at stave til processor! :)
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.