Juist gebruik van Transactions

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Jordy nvt

Jordy nvt

24/05/2011 17:24:39
Quote Anchor link
Voor mijn website heb ik een aantal ingewikkelde scripts van legers die naar elkaar toe trekken, elkaar aanvallen, etcetera. Dit moet uiteraard goed gebeuren en daarom maak ik gebruik van Transactions. Tenminste, dat wil ik gaan doen want het lukt niet erg goed. Zo krijg ik ze reactie dat ik geen Select query enzo mag gebruiken. Kan iemand mij helpen?

Dit is mijn code tot nu toe van één van de vele plekken waar ik Transactions wil gaan gebruiken. De code is een voorbeeld en draait dus niet live, maar het principe wil ik overal gaan toepassen.


Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
$query
="start transaction";
$result = mysql_query($query, $db);

$query_select="SELECT Id, Aantal_soldaten FROM moving_actions WHERE From_user_id='".$my_user_id."' AND Arrivaltime<NOW()";
$query_select = mysql_query($query_select, $db);
if (mysql_num_rows($result_select) > 0){// Als resultaat > 0 is
    while($row=mysql_fetch_array($result)){

        //ok, er zijn troepen gevonden die aangekomen zijn
        $id = $row['Id'];
        $aantal_soldaten = $row['Aantal_soldaten'];
        //Hier komt de hele berekening die ophaalt hoeveel soldaten de tegenstander heeft, wat de uitslag is, hoeveel soldaten er over blijven en of er grondstoffen zijn geplunderd

        //stuur soldaten terug naar huis

        if ($overgebleven_soldaten>0){
            $query_update="Update moving_actions SET Aantal_soldaten='".$overgebleven_soldaten."' AND Terug_naar_huis='TRUE' AND Aankomsttijd='".$nieuwe_aankomsttijd."' AND Geplunderde_grondstoffen='".$geplunderde_grondstoffen."' WHERE Id='".$id."'";
            $query_update = mysql_query($query_update, $db);
        }

        //Haal geplunderde grondstoffen van aangevallen dorp af:
        if ($geplunderde_grondstoffen>0){
            $query_update2="Update dorpen SET Grondstoffen=Grondstoffen-'".$geplunderde_grondstoffen."' WHERE Dorp_id='".$aangevallen_dorp_id."'";
            $query_update2 = mysql_query($query_update2, $db);
        }

    }
//einde voor while
}

if((!$query_select) || (!$query_update) || (!$query_update2)){
    mysql_query("ROLLBACK");
}
else{
    mysql_query("COMMIT");    
}
else{
    //Geweldig, alle queries zijn gelukt, er kan niks tussengekomen zijn.
    //echo "De queries zijn succesvol uitgevoerd";

}
?>
Gewijzigd op 24/05/2011 18:32:02 door Jordy nvt
 
PHP hulp

PHP hulp

24/04/2024 22:54:42
 
Vincent Huisman

Vincent Huisman

24/05/2011 18:17:26
Quote Anchor link
je hebt geen sql fout afhandeling
 
Tikkes C

Tikkes C

24/05/2011 18:19:34
Quote Anchor link
waar komt $result_select vandaan? en van $result vraag je een array, maar dit is gewoon een start transaction statement?
Gewijzigd op 24/05/2011 18:20:34 door Tikkes C
 
Jordy nvt

Jordy nvt

24/05/2011 18:31:37
Quote Anchor link
@Vincent, eigenlijk is het een soort van voorbeeldscript wat ik later ga toepassen op al mijn echte scripts.

@Tikkes C, $result_select komt van de query daarboven waar ik per ongeluk een verkeerde variabele heb gebruikt. Zoals ik al zei is het script een voorbeeld, het gaat meer om de toepassing van Transactions.
 
Kees Schepers

kees Schepers

25/05/2011 09:47:15
Quote Anchor link
De tip van Vincent is misschien wat karig, maar hij denk ik bedoeld is dat als de foutafhandeling beter voor elkaar hebt transactions ook meer zin hebben.

Het nut van transactions is, dat als je meer database mutaties doet en deze allemaal verwant aan elkaar zijn en allemaal aan een stuk moeten lukken, biedt het een uitkomst. Je kunt het terug rollen door ROLLBACK aan te roepen als er ergens iets fout gaat in je script (syntax en fatale fouten uitgesloten). Uiteraard moet je wel goed controleren of er iets fout gaat.

Nog iets; 2 maal ELSE in een IF structure kan niet, er kan maar een ELSE zijn, misschien dat je ELSEIF bedoeld.


Wat is je storage engine van de tabellen moving_actions en dorpen? Als je MySQL gebruikt met standaard instellingen waarschijnlijk MyIsam en die ondersteund zover ik weet geen transactions. InnoDB bijvoorbeeld wel. Je zult dan de engine moeten aanpassen wat kan met de query:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
ALTER TABLE moving_actions SET ENGINE innoDB;
 
Jordy nvt

Jordy nvt

25/05/2011 09:50:44
Quote Anchor link
Nee, ik maak inderdaad gebruik gebruik van InnoDB. Die twee keer else zijn inderdaad fout en de eerste moet elseif zijn.

Maar klopt het wel met die SELECT query? Er wordt ook gezegd dat die verkeerd zijn, maar wat is de reden daarvoor? En wat moet er dan precies gebeuren en veranderen?
 
Arjan -

Arjan -

25/05/2011 09:55:49
Quote Anchor link
Eén tip: Verdiep je in PDO (http://www.phphulp.nl/php/tutorial/overig/pdo-verbinden-met-verschillende-databases/534/)

Hiermee is het zeer eenvoudig transacties uit te voeren en je hebt gelijk een goede database driver voor de toekomst!
 
Jordy nvt

Jordy nvt

25/05/2011 09:57:12
Quote Anchor link
Probleem is dat ik al zover gevorderd ben dat het enorm veel werk is om alles aan te passen. Ik ga later zeker alles omzetten naar PDO, alleen nu nog niet:-) Hopelijk is het niet erg, maar ik heb liever even een script met MySQL en Transactions:-)

Het lijkt mij niet erg moeilijk, maar het is apart dat er op internet zo weinig over te vinden is...
 
Kees Schepers

kees Schepers

25/05/2011 09:57:13
Quote Anchor link
Met de select query is niks (op evt injectie na). Je zou alleen de START TRANSACTION na de selectquery beter kunnen uitvoeren gezien de select query niet terug gedraait hoeft te worden.
 
Pim -

Pim -

25/05/2011 10:14:30
Quote Anchor link
Transactions zijn ook veel sneller!
 
Jordy nvt

Jordy nvt

25/05/2011 16:58:30
Quote Anchor link
Ok, mijn code wordt als volgt. Voorkom ik dan dat ik dubbele afwerkingen te verwerken krijg? Ook als deze enkele tientallen keren per seconde tegelijk wordt opgevraagd?

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
$query_select
="SELECT Id, Aantal_soldaten FROM moving_actions WHERE From_user_id='".$my_user_id."' AND Arrivaltime<NOW()";
$query_select = mysql_query($query_select, $db);
if (mysql_num_rows($result_select) > 0){// Als resultaat > 0 is

    $query="start transaction";
    $result = mysql_query($query, $db);

    while($row=mysql_fetch_array($result)){

        //ok, er zijn troepen gevonden die aangekomen zijn
        $id = $row['Id'];
        $aantal_soldaten = $row['Aantal_soldaten'];
        //Hier komt de hele berekening die ophaalt hoeveel soldaten de tegenstander heeft, wat de uitslag is, hoeveel soldaten er over blijven en of er grondstoffen zijn geplunderd

        //stuur soldaten terug naar huis

        if ($overgebleven_soldaten>0){
            $query_update="Update moving_actions SET Aantal_soldaten='".$overgebleven_soldaten."' AND Terug_naar_huis='TRUE' AND Aankomsttijd='".$nieuwe_aankomsttijd."' AND Geplunderde_grondstoffen='".$geplunderde_grondstoffen."' WHERE Id='".$id."'";
            $query_update = mysql_query($query_update, $db);
        }

        //Haal geplunderde grondstoffen van aangevallen dorp af:
        if ($geplunderde_grondstoffen>0){
            $query_update2="Update dorpen SET Grondstoffen=Grondstoffen-'".$geplunderde_grondstoffen."' WHERE Dorp_id='".$aangevallen_dorp_id."'";
            $query_update2 = mysql_query($query_update2, $db);
        }

    }
//einde voor while

    if((!$query_select) || (!$query_update) || (!$query_update2)){
        mysql_query("ROLLBACK");
    }
else{
        mysql_query("COMMIT");    
        //Geweldig, alle queries zijn gelukt, er kan niks tussengekomen zijn.
        //echo "De queries zijn succesvol uitgevoerd";

    }
}
//script hoeft geen actie uit te voeren, er is namelijk niemand onderweg
?>
 
Jordy nvt

Jordy nvt

27/05/2011 09:37:56
Quote Anchor link
Nee, het script klopt toch niet. Wat nu als ik selecteer en iemand anders doet dit tegelijk? Dan moet de Select query toch ook in de Transactie? Kan plz iemand helpen want ik snap er niks meer van,
 
Jordy nvt

Jordy nvt

29/05/2011 20:30:57
Quote Anchor link
Nog 1 bump, zou iemand mij kunnen helpen want ik kom er niet meer uit, hoeveel ik ook zoek op het internet.
 
Arjan -

Arjan -

30/05/2011 10:02:05
Quote Anchor link
Je foutafhandeling is verkeerd, waardoor de code niet gaat werken zoals jij verwacht. De query variabelen worden bij elke loop overschreven waardoor bij de controle onderaan je script alleen de waarde van de laatste loop wordt meegenomen. Je kan beter binnen je loop een controle plaatsen die bijv. de variabele error op true zet wanneer een query niet is gelukt. Hierna hoef je alleen te kijken of de variabele $error op true staat. Zo ja, rollback. Anders committen.
En een select binnen je transactie is zinloos. Je hoort al boven je while loop te controleren of de select query is gelukt, aangezien de while loop daar afhankelijk van is.

Maar wat gaat er precies mis, want uit je verhaal maak ik op dat je geen foutmeldingen krijgt toch?
Gewijzigd op 30/05/2011 10:10:35 door Arjan -
 
Jordy nvt

Jordy nvt

30/05/2011 10:41:06
Quote Anchor link
Bedankt voor je reactie! Ik krijg inderdaad geen foutmelding, maar stel dat ik die Select query uitvoer. Het blijkt dat er een leger is aangekomen en vervolgens moet de aanval worden afgehandeld in een Transactie. Alleen het is dan toch mogelijk dat tussen die Select query en de Transactie een andere query komt? Dus dat het zo gaat:

Select query gebruiker 1 geeft aan dat er een leger is aangekomen
Select query gebruiker 2 geef ook aan dat er een leger is aangekomen
Transaction gebruiker 1 wordt gestart
Transactien gebruiker 2 wordt gestart.

Volgensmij gaat het dan fout. Of is het helemaal goed als ik eerst een Select query uitvoer en als de waar de >0 is dat dan de transactie begint? En moet ik dan binnen die transactie nog op dingen controleren? Of klopt mijn script van 4 posts geleden?
 
Arjan -

Arjan -

30/05/2011 10:49:29
Quote Anchor link
Pas wanneer de actie commit wordt gegeven worden de gezevens daadwerkelijk in de database hezet. Bij mijn weten is het niet nodig om een tabel of rij te locken. Innodb lockt standaard de gebruikte tabelrij(en). Google verschaft hier ook veel informatie over.

En zie mijn opmerking over foutafhandeling om het script beter te laten werken.
Gewijzigd op 30/05/2011 10:52:31 door Arjan -
 
Jordy nvt

Jordy nvt

30/05/2011 17:14:31
Quote Anchor link
Over de foutafhandeling heb ik gelezen maar zoals ik al zei is het een voorbeeld, dus dat doe ik er allemaal nog in. Het ging meer om het principe, maar bedankt:-)


Zou je dus kunnen zeggen dat onderstaande script helemaal goed werkt en dus juist gebruik maakt van Transactions zonder dat er dubbele acties kunnen gebeuren? (Behalve dan die foutafhandeling)
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
$query_select
="SELECT Id, Aantal_soldaten FROM moving_actions WHERE From_user_id='".$my_user_id."' AND Arrivaltime<NOW()";
$query_select = mysql_query($query_select, $db);
if (mysql_num_rows($result_select) > 0){// Als resultaat > 0 is

    $query="start transaction";
    $result = mysql_query($query, $db);

    while($row=mysql_fetch_array($result)){

        //ok, er zijn troepen gevonden die aangekomen zijn
        $id = $row['Id'];
        $aantal_soldaten = $row['Aantal_soldaten'];
        //Hier komt de hele berekening die ophaalt hoeveel soldaten de tegenstander heeft, wat de uitslag is, hoeveel soldaten er over blijven en of er grondstoffen zijn geplunderd

        //stuur soldaten terug naar huis

        if ($overgebleven_soldaten>0){
            $query_update="Update moving_actions SET Aantal_soldaten='".$overgebleven_soldaten."' AND Terug_naar_huis='TRUE' AND Aankomsttijd='".$nieuwe_aankomsttijd."' AND Geplunderde_grondstoffen='".$geplunderde_grondstoffen."' WHERE Id='".$id."'";
            $query_update = mysql_query($query_update, $db);
        }

        //Haal geplunderde grondstoffen van aangevallen dorp af:
        if ($geplunderde_grondstoffen>0){
            $query_update2="Update dorpen SET Grondstoffen=Grondstoffen-'".$geplunderde_grondstoffen."' WHERE Dorp_id='".$aangevallen_dorp_id."'";
            $query_update2 = mysql_query($query_update2, $db);
        }

    }
//einde voor while

    if((!$query_select) || (!$query_update) || (!$query_update2)){
        mysql_query("ROLLBACK");
    }
else{
        mysql_query("COMMIT");    
        //Geweldig, alle queries zijn gelukt, er kan niks tussengekomen zijn.
        //echo "De queries zijn succesvol uitgevoerd";

    }
}
//script hoeft geen actie uit te voeren, er is namelijk niemand onderweg
?>
 
Jordy nvt

Jordy nvt

31/05/2011 20:19:37
Quote Anchor link
Iemand die het hopelijk kan bevestigen?
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.