PDO voert mijn statement niet uit?

    • PDO voert mijn statement niet uit?

      Heren,

      Solved the issue, kinda was a stupid move..
      Ik voerde dus een execute uit met een parameter.. Alleen die parameter gaf ik niet door aan de statement. Nadat ik "npc_id" vervangen had voor een '?' werd deze correct uitgevoerd.. Stupid me..


      Ik ben bezig met het ontwikkelen van een eigen tekst-based game, en daarvoor heb ik random spawned NPC's.. Nu bieden deze NPC's items aan.
      Echter gaat alles goed, afschrijven van geld etcetera. Alleen de onderstaande query word niet uitgevoerd door PDO..

      PHP Source Code

      1. public function sellNpcItems($items, $quantity, $npc_id)
      2. {
      3. try
      4. {
      5. $sql = "UPDATE npc_items SET available = CASE item_id";
      6. for($i=0;$i<count($items);$i++)
      7. {
      8. $sql .= " WHEN ".$items[$i]." THEN available - ".$quantity[$i];
      9. }
      10. $sql .= " ELSE available END WHERE npc_id = ".$npc_id;
      11. $sql = $this->dbh->prepare($sql);
      12. $sql->execute(array($npc_id));
      13. $this->dbh->commit();
      14. $result = $sql->fetchAll(PDO::FETCH_ASSOC);
      15. return $result;
      16. }
      17. catch(PDOException $e){echo 'Error ! '.$e->getMessage();die();}
      18. }
      Laat alles zien


      Aan de fetchAll kan het niet liggen, deze heb ik er al tussen uit gehad. De query word gewoon niet uitgevoerd. Wanneer ik ook een "print_r" uitvoer op SQL is de output een normale query welke ik kan kopiëren en uit kan voeren op de database zonder enige foutmelding.

      Vraag is nu ... Waar gaat het fout, waarom voert PDO het niet uit maar als ik het handmatig doe word het wel uitgevoerd?

      Ohja, dit is de output van de SQL parameter wanneer ik een item heb "gekocht".


      SQL-Query

      1. PDOStatement Object ( [queryString] => UPDATE npc_items SET available = CASE item_id WHEN 57 THEN available - 1 ELSE available END WHERE npc_id = 1 )
      Alvast bedankt voor het kijken heren ;)

      Kevin.

      Post werd 1x aangepast, het laatst door KampenRepair ().

    • Als ik het goed begrijp kun je meerdere items (in verschillende) hoeveelheden tegelijkertijd kopen? Maar zou je dan niet meerdere queries moeten gebruiken? Alleen het eerste WHEN THEN blok wat voldoet wordt dan toch maar uitgevoerd? En ook weet je dan niet precies welke items iemand ontvangt? Of ik moet niet goed begrijpen wat deze methode nu concreet doet?

      En is de controle nu uberhaupt wel goed? Zou dat niet zoiets moeten zijn als WHEN $items[$i] AND available >= $quantity[$i], oftewel, er moeten minstens zoveel items op voorraad zijn om er zoveel af te nemen? Maar eigenlijk is deze hele constructie niet echt goed, want deze locked de resource niet, dus als meerdere mensen tegelijkertijd hetzelfde item willen kopen (zodanig dat je in totaliteit eigenlijk meer koopt dan er op voorraad is) dan gaat dat misschien nog lukken ook.

      Zou je eens kunnen uitleggen wat sellNpcItems() nu precies zou moeten doen, en wat is de precieze betekenis van $items, $quantity en $npc_id? En zou je $items en $quantity niet kunnen combineren tot simpelweg een $quantity array, waarbij de index hiervan het item-id is?
    • Het systeem is vrij complex maar een korte versie;

      Op een kaart verschijnt een NPC welke een x aantal items aanbied met een bepaald vooraf gegenereerd aantal.
      Gebruikers die de NPC zien (hij blijft niet lang) kunnen items met korting hier kopen.

      sellNpcItems is simpelweg de functie welke de items in mindering brengt op de tabel waar de hoeveelheid van het item op de NPC is geregistreerd.

      Je hebt gelijk dat de check voor "of er nog genoeg items zijn" niet helemaal correct is. Er zou eigenlijk achter de WHERE npc_id = 1 ook een AND available >= $quantity[$i] moeten.. daar heb je gelijk in.

      Het is eigenlijk nu:
      WHEN available CASE item_id(field in NPC_items) WHEN 57 (item_id) THEN available - $quantity ELSE available END
    • Mja, maar de methode ziet eruit alsof je een reeks items koopt of kunt kopen (mogelijk met verschillende hoeveelheden), ik vermoed dat enkel het eerste item in de lijst wordt aangeschaft met bovenstaande syntax omdat waarschijnlijk enkel het record dat betrekking heeft op de eerste CASE die voldoet wordt geupdate. En daarbij is er dus helemaal geen controle of er wel genoeg items zijn.

      Ben je nagegaan dat als een speler meerdere items van een NPC koopt dat alle hoeveelheden (zowel van verkochte als aangekochte) van items na afloop kloppen?

      En dan heb je nu dus nog het potentiële probleem van een gebrek aan concurrency. Voor het bijwerken van hoeveelheden die beheerd worden door en overgedragen worden tussen meerdere partijen dienen voor een goed verloop in bijna alle gevallen transacties ingezet te worden, waarbij de hoeveelheid eerst "gereserveerd" wordt zodat deze enkel kan overgedragen worden aan één andere partij. Dit zodat er niet, door een potentieel parallel verloop van meerdere queries, ineens hoeveelheden uit het niets gecreëerd worden of in het niets verdwijnen.


      Is het niet handiger om dit net zoals bij een order op te splitsen in orderregels? Dan heb je meer controle over de gang van zaken. En mogelijk moet je ook rekening houden met het volgende: stel dat iemand zijn order heeft ingeklopt, maar iemand was hem net voor waardoor een of meer items niet meer in de gewenste hoeveelheid verkrijgbaar zijn. Wat gebeurt er dan? Wordt de hele order teruggedraaid, of gedeeltelijk doorgevoerd? Dit lijkt mij verwarrend, stel dat je o.a. 5 keer item A hebt gekocht en dat pas later blijkt dat item A niet beschikbaar was. Daarom lijkt mij dit reden te meer (ook qua eenvoud) om het gewoon niet mogelijk te maken om batches te kopen, maar slechts één item (in een bepaalde hoeveelheid) per keer.
    • FangorN wrote:

      Mja, maar de methode ziet eruit alsof je een reeks items koopt of kunt kopen (mogelijk met verschillende hoeveelheden), ik vermoed dat enkel het eerste item in de lijst wordt aangeschaft met bovenstaande syntax omdat waarschijnlijk enkel het record dat betrekking heeft op de eerste CASE die voldoet wordt geupdate. En daarbij is er dus helemaal geen controle of er wel genoeg items zijn.

      Ben je nagegaan dat als een speler meerdere items van een NPC koopt dat alle hoeveelheden (zowel van verkochte als aangekochte) van items na afloop kloppen?

      En dan heb je nu dus nog het potentiële probleem van een gebrek aan concurrency. Voor het bijwerken van hoeveelheden die beheerd worden door en overgedragen worden tussen meerdere partijen dienen voor een goed verloop in bijna alle gevallen transacties ingezet te worden, waarbij de hoeveelheid eerst "gereserveerd" wordt zodat deze enkel kan overgedragen worden aan één andere partij. Dit zodat er niet, door een potentieel parallel verloop van meerdere queries, ineens hoeveelheden uit het niets gecreëerd worden of in het niets verdwijnen.


      Is het niet handiger om dit net zoals bij een order op te splitsen in orderregels? Dan heb je meer controle over de gang van zaken. En mogelijk moet je ook rekening houden met het volgende: stel dat iemand zijn order heeft ingeklopt, maar iemand was hem net voor waardoor een of meer items niet meer in de gewenste hoeveelheid verkrijgbaar zijn. Wat gebeurt er dan? Wordt de hele order teruggedraaid, of gedeeltelijk doorgevoerd? Dit lijkt mij verwarrend, stel dat je o.a. 5 keer item A hebt gekocht en dat pas later blijkt dat item A niet beschikbaar was. Daarom lijkt mij dit reden te meer (ook qua eenvoud) om het gewoon niet mogelijk te maken om batches te kopen, maar slechts één item (in een bepaalde hoeveelheid) per keer.

      Je hebt wel helemaal gelijk, maar het is in mijn ogen op deze manier een veel betere en mooiere aanpak. De functie werkt nu in ieder geval wel goed. Als ik 5 verschillende items koop ontvang ik ze ook daadwerkelijk alle 5.

      Tevens maak ik er ook een transactie nu van. Zodat er eerst een controle plaatsvind zodat er geen min getallen kunnen voorkomen. Dan word de aankoop gerollbacked en treed er een foutmelding op. Ik ben wel blij met je visie het helpt mij mijn denken ook te verbeteren. Ik zal eens kijken naar de mogelijkheid voor reservering toe te voegen. Zodat op de achtergrond al een check gebeurt of de items er nog zijn indien ja deze te reserveren. Wanneer de aankoop word afgebroken worden ze pas weer vrijgegeven. Eigenlijk een soort van live counter op de aantallen op het moment dat iemand deze selecteerd. (Ben van plan dit middels JSON te doen maar denk dat daar wel een beter alternatief voor is) even onderzoeken dit dus.
    • Het in een transactie plaatsen van queries garandeert niet de ondeelbaarheid van een reeks acties binnen zo'n transactie, twee of meer transacties kunnen nog steeds tegelijkertijd plaatsvinden.

      Het ondeelbaar maken van meerdere acties bereik je alleen door binnen de transactie records te vergrendelen met FOR UPDATE. Dus het "reserveren" waar jij het over hebt is (zowel in mijn voorstel als in jouw aanpak) een absolute voorwaarde voor correcte werking.

      Lees de volgende paragraaf eens door, deze verwoordt mogelijk beter wat er gebeurt tijdens een transactie.

      En ook zul je dus de situatie moeten ondervangen dat de transactie in het geheel niet doorgaat. Dus stel dat je een batch niet in zijn geheel kunt kopen, dan zal deze hele batch niet doorgaan, immers, het idee van een transactie is dat deze in het geheel wordt uitgevoerd, of in het geheel niet. Daarom stelde ik voor om de afmeting van de "ondeelbare actie" op item-niveau te doen, in plaats van op bestelling-niveau zodat je niet alle items opnieuw hoeft in te kopen als er toevallig één item niet meer in de juiste hoeveelheid beschikbaar is omdat iemand anders je net voor was. Zo gaat het in een webshop ook: als 1 item niet beschikbaar is zal niet ineens je hele bestelling worden geannuleerd :p.