[PHP/MySQL] Multi-user probleem met schrijven database

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Onbekend
  • Registratie: Juni 2005
  • Laatst online: 17:19
Ik heb (na veel werk) lange php scrips geschreven die gebruik maken van MySQL.

Eerst open ik de connectie naar MySQL, vervolgens lees ik de tabel in en sluit de connectie weer.
Nu ga ik de data verwerken.
En daarna open ik de connectie weer, wijzig bepaalde velden, en sluit weer de connectie.

Tot nu toe verloopt dat prima.


Het probleem zit nu tijdens de dataverwerking.
Op dat moment hebben andere scripts namelijk toegang tot de database.
Stel dat die scripts bepaalde cellen veranderen, en daarna dit script ook diezelfde cellen veranderd, heb ik een probleem.

Een mogelijkheid zou zijn om de connectie tijdens de gehele verwerking open te houden, maar sommige scripts doen er ruim 10 seconden over om de rekenen. Er zouden dan maar 6 pagina's per minuut gegenereerd kunnen worden. Dat kan natuurlijk niet. :)

Ik zou ook kunnen detecteren of die cellen nog hetzelfde zijn op het moment dat ik ze ga overschrijven. Maar dan zit ik met het punt dat als de cellen anders zijn, het script weer 10 seconden moet gaan rekenen (en vervolgens hopen dat die cel gelijk gebleven is).

Ik verwacht dat ik niet de enige ben met dit probleem, maar met Google heb ik niets kunnen vinden.
Ja, alleen de basis om cellen te schrijven en te lezen. Maar niet het voorkomen van dit probleem.

Iemand ervaring hiermee?

Speel ook Balls Connect en Repeat


Acties:
  • 0 Henk 'm!

  • orf
  • Registratie: Augustus 2005
  • Nu online

orf

Je kunt locken om te voorkomen dat andere scripts updates of inserts doen, select statements kunnen dan wel gewoon.

Waarom moet een script 10 seconden rekenen?

Acties:
  • 0 Henk 'm!

  • om3ega
  • Registratie: Maart 2001
  • Laatst online: 00:11
http://dev.mysql.com/doc/refman/5.0/en/insert-delayed.html

The DELAYED option for the INSERT statement is a MySQL extension to standard SQL that is very useful if you have clients that cannot or need not wait for the INSERT to complete. This is a common situation when you use MySQL for logging and you also periodically run SELECT and UPDATE statements that take a long time to complete.

Acties:
  • 0 Henk 'm!

  • Onbekend
  • Registratie: Juni 2005
  • Laatst online: 17:19
Sommige scripts halen informatie van m'n thuiscomputer op. Aangezien mijn computer niet al te snel is, kost het enige tijd voordat die data binnen is om verder te verwerken.

Eigenlijk moet ik dataverwerking zeggen i.p.v. rekenen.

Andere scripts zijn wel snel hoor (< 1 sec).

Speel ook Balls Connect en Repeat


Acties:
  • 0 Henk 'm!

  • Onbekend
  • Registratie: Juni 2005
  • Laatst online: 17:19
@om3ega:
Dit is volgens mij voor lange schrijfbewerkingen in MySQL.
Maar dat is helemaal niet het probleem.

Speel ook Balls Connect en Repeat


Acties:
  • 0 Henk 'm!

Verwijderd

Multi-user probleem dus. Heeft verder niets met SQL te maken. Je zult iets moeten maken waarbij je bijhoudt welke cellen gelockt zijn en dat anderen die gelockte cellen alleen mogen lezen bijv.

Probleem is het vrijgeven van de lock, aangezien het sluiten van de browser niet afgevangen wordt, dus iets van een time-out in bouwen. Zelf heb ik iets dergelijks gemaakt in VS.NET, waren wel voorbeelden te vinden op internet.

Kijk eens naar semaphores bijv. Je zult in een aparte datastructuur moeten bijhouden welke cellen gelockt zijn. Is allemaal nog even wat werk, succes daarom.

Nuttige links:

http://www.phpdig.net/ref/rn57.html
http://www.phpbuilder.com/manual/en/ref.sem.php (misschien iets minder voor jou).

Good luck 8-)

Acties:
  • 0 Henk 'm!

  • orf
  • Registratie: Augustus 2005
  • Nu online

orf

Met ingore_user_abort kun je het sluiten van de browser wel opvangen. In je zelfde PHP script moet de lock dan in ieder geval opgeheven worden.

Acties:
  • 0 Henk 'm!

Verwijderd

orf schreef op zaterdag 07 oktober 2006 @ 18:29:
Met ingore_user_abort kun je het sluiten van de browser wel opvangen. In je zelfde PHP script moet de lock dan in ieder geval opgeheven worden.
Wedden dat dat niet werkt als het script is uitgevoerd en iemand sluit de browser? Het is onmogelijk om serverside te bepalen of iemand zijn browser nog open heeft, behalve met iets van javascript wellicht.

http://nl3.php.net/ignore_user_abort
Weet je zeker dat het daar mee kan? Lijkt me heel iets anders :?

Acties:
  • 0 Henk 'm!

  • megamuch
  • Registratie: Februari 2001
  • Laatst online: 08-12-2024

megamuch

Tring Tring!

Het gaat toch om SQL? Transacties met INNODB wellicht een optie? Blijft je data iig hetzelfde tot het moment dat jij de transactie sluit.

Verstand van Voip? Ik heb een leuke baan voor je!


Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

(jarig!)
Verwijderd schreef op zaterdag 07 oktober 2006 @ 18:31:
Wedden dat dat niet werkt als het script is uitgevoerd en iemand sluit de browser? Het is onmogelijk om serverside te bepalen of iemand zijn browser nog open heeft, behalve met iets van javascript wellicht.

http://nl3.php.net/ignore_user_abort
Weet je zeker dat het daar mee kan? Lijkt me heel iets anders :?
Dat zorgt er voor dat het script niet zomaar ineens stopt met werken, maar door gaat tot het exit-statement of het eind van de code.
megamuch schreef op zaterdag 07 oktober 2006 @ 18:50:
Het gaat toch om SQL? Transacties met INNODB wellicht een optie? Blijft je data iig hetzelfde tot het moment dat jij de transactie sluit.
En dat zal niet noodzakelijkerwijs het probleem van de topicstarter oplossen, aangezien een transactie er alleen maar voor zorgt dat tijdens die transactie de wijzigingen van anderen niet zichtbaar zijn en dat de wijzigingen van deze niet door anderen te bekijken zijn... Als gebruiker X zijn scherm opent (script executie) en dan de data in het form gaat lopen veranderen is er geen actieve verbinding met de server meer open. Gebruiker Y kan ook zo'n form openen, de velden wijzigen en opslaan.

Het is al eerder gezegd, maar wat de topicstarter zal moeten doen is een systeem opzetten waarbij wordt voorkomen dat anderen, de cellen die door gebruiker X bewerkt moeten gaan worden, ook aan mogen passen.
Met SQL-transacties wordt iets dergelijks weliswaar opgelost, maar in een andere context.

Als je alleen maar geinteresseerd bent in een check of de records al gewijzigd zijn sinds het openen van het form dan is het wellicht een goed idee om de tijd waarop het form gegenereerd werd ook mee te sturen bij de submit, zodat je kan checken of de records sindsdien gewijzigd zijn.

Acties:
  • 0 Henk 'm!

  • Onbekend
  • Registratie: Juni 2005
  • Laatst online: 17:19
@ACM: Ik zal daar vanmiddag gaan kijken of ik op die manier dat probleem kan aanpakken.


Voor de duidelijkheid heb ik het probleem anders weergegeven.
Ik hoop dat dit nu duidelijker is:
Afbeeldingslocatie: http://img183.imageshack.us/img183/948/tijdslijnwb4.png

Speel ook Balls Connect en Repeat


Acties:
  • 0 Henk 'm!

Verwijderd

Ik bedenk nu net iets (geen ervaring hiermee ofzo):

Maak een tabel aan waarin de bewerking wordt opgeslagen. Met een server-side script worden al die bewerkingen vervolgens uitgevoerd op de echte tabel.

Hierdoor komt er gewoon in de database te staan:
+1
+1

En dan weet die database wat er moet gebeuren.

Ik weet natuurlijk niet wat je wilt met het script, maar dit zou er voor zorgen dat de data altijd accessible is, en dat acties niet ongedaan gemaakt worden. Het nadeel is natuurlijk dat een gebruiker een +1 / -1 bewerking zou kunnen uitvoeren op verouderde data.

[ Voor 29% gewijzigd door Verwijderd op 08-10-2006 14:28 ]


Acties:
  • 0 Henk 'm!

  • Onbekend
  • Registratie: Juni 2005
  • Laatst online: 17:19
In die richting zit ik wel te denken. Maar sommige rekenbewerkingen zijn te complex om zo op te schrijven omdat ze met 5 verschillende (veranderlijke) variablen werken.

Speel ook Balls Connect en Repeat


Acties:
  • 0 Henk 'm!

  • jochemd
  • Registratie: November 2000
  • Laatst online: 24-08 12:31
Ook onbekend schreef op zaterdag 07 oktober 2006 @ 12:08:
Eerst open ik de connectie naar MySQL, vervolgens lees ik de tabel in en sluit de connectie weer.
Nu ga ik de data verwerken.
En daarna open ik de connectie weer, wijzig bepaalde velden, en sluit weer de connectie.
(..)
Stel dat die scripts bepaalde cellen veranderen, en daarna dit script ook diezelfde cellen veranderd, heb ik een probleem.

Een mogelijkheid zou zijn om de connectie tijdens de gehele verwerking open te houden, maar sommige scripts doen er ruim 10 seconden over om de rekenen. Er zouden dan maar 6 pagina's per minuut gegenereerd kunnen worden. Dat kan natuurlijk niet. :)
Gewoon je connecties open houden en waar je de data selecteert in plaats van een SELECT een SELECT FOR UPDATE doen. En als je dan niet tevreden bent over de performance dan open je toch gewoon wat meer connecties?

Acties:
  • 0 Henk 'm!

Verwijderd

Misschien een gekke hoor... maar heb laatst toevallig een "vrij eenvoudige" wijze gevonden om te checken op wijzigingen:

Wanneer script 2 de waarde van X ophaalt... weet hij dat deze op dit moment bijvoorbeeld 12 is, blijkbaar wijzigd deze waarde bij elke schrijfactie, wanneer er een ander script zijn ding heeft gedaan zal deze waarde dus op >13 staan. Als ik er nu dus vanuit ga dat X=12 betekent dat er geen wijzigingen geweest zijn in de tussentijd, kun je dit gebruiken in je Update query, UPDATE x WHERE ID=waarde AND X=12, bij falen kun je er dus zo'n beetje vanuit gaan dat de waarde inmiddels is gewijzigd!

Dit is vrij dirty volgens mij, maar heeft in ieder geval het gewenste resultaat zonder ingewikkelde oplossingen voor locking enzo.

Acties:
  • 0 Henk 'm!

  • Onbekend
  • Registratie: Juni 2005
  • Laatst online: 17:19
Die mogelijkheid is er inderdaad, maar ik blijf met 1 probleem zitten.

Namelijk als de data is veranderd, zal de dataverwerking opnieuw moeten gebeuren.
Stel dat bij een lang script 3x achter elkaar de data is veranderd (door een snel script), kom ik boven de 30 seconde "execution time" heen.
Hier krijgt de gebruiker een foutmelding terug. Ik verwacht dat dat binnen korte tijd heel veel zal gebeuren. Vandaar dat ik nu al een oplossing zoek.

Ik zoek eigenlijk iets in de richting van een soort wachtrij zodat elke script aan de beurt komt, zonder dat ik veel snelheid verlies.

Ik zou het niet erg vinden als elke gebruiker 10 seconden voor een pagina moet wachten.
Maar ik vind het wel erg als een gebruiker een foutmelding door een time-out krijgt.

Speel ook Balls Connect en Repeat


Acties:
  • 0 Henk 'm!

  • gvanh
  • Registratie: April 2003
  • Laatst online: 02-12-2023

gvanh

Webdeveloper

De foutmelding omtrent de maximum execution time is niet het grootste probleem. Er is enerzijds de mogelijkheid om via ini_set("max_execution_time", <nieuw>) deze te verlengen. Als je provider dat niet toestaat, dan kun je ook door middel van flush() ervoor zorgen dat de teller wordt ge-reset.

Zoiets als dit:
PHP:
1
2
3
4
5
$sql = "query"
if ( execute($sql) == niet goed gegaan ) {
  echo "We zijn nog steeds bezig. Even geduld nog ... ";
  flush();
}

Acties:
  • 0 Henk 'm!

  • skabouter
  • Registratie: Oktober 2000
  • Laatst online: 20-08 08:55

skabouter

Skabouter

Ook onbekend schreef op maandag 09 oktober 2006 @ 19:21:
Die mogelijkheid is er inderdaad, maar ik blijf met 1 probleem zitten.

Namelijk als de data is veranderd, zal de dataverwerking opnieuw moeten gebeuren.
Stel dat bij een lang script 3x achter elkaar de data is veranderd (door een snel script), kom ik boven de 30 seconde "execution time" heen.
Hier krijgt de gebruiker een foutmelding terug. Ik verwacht dat dat binnen korte tijd heel veel zal gebeuren. Vandaar dat ik nu al een oplossing zoek.

Ik zoek eigenlijk iets in de richting van een soort wachtrij zodat elke script aan de beurt komt, zonder dat ik veel snelheid verlies.

Ik zou het niet erg vinden als elke gebruiker 10 seconden voor een pagina moet wachten.
Maar ik vind het wel erg als een gebruiker een foutmelding door een time-out krijgt.
Wat je kunt doen is kijken of de waarde inmiddels gewijzigd is, is dit het geval dan gooi je een lock op de tabel en voer je de functie waar je mee bezig bent nogmaals uit, daarna haal je de lock van de tabel af en kunnen andere functies met de nieuwe waarde weer verder rekenen....

Het afvangen van het sluiten van de browser is makkelijk te realiseren in javascript, het nadeel is wel dat het ook weer makkelijk te omzeilen / uit te schakelen is voor de gebruiker.

[ Dislect ]


Acties:
  • 0 Henk 'm!

  • xces
  • Registratie: Juli 2001
  • Laatst online: 20-09 16:56

xces

To got or not to got..

Ik heb niet alle reacties gelezen, maar heb je al eens aan subversion gedacht? Ik heb het zelf nog niet geimplementeerd, maar zit er wel over na te denken;

Voordat je het record "opent" sla je de current state op. Vervolgens ga je berekeningen uitvoeren. Vlak voordat je op gaat slaan controleer je of het record in de tussentijd gewijzigd is t.o.v. het origineel, en zo niet schrijf je het weg. Zo wel, dan kun je de user vragen wat hij wil doen.. (indelen naar eigen inzicht :p)

Ideetje?

Acties:
  • 0 Henk 'm!

Verwijderd

Ook onbekend schreef op maandag 09 oktober 2006 @ 19:21:
Die mogelijkheid is er inderdaad, maar ik blijf met 1 probleem zitten.

Namelijk als de data is veranderd, zal de dataverwerking opnieuw moeten gebeuren.
Stel dat bij een lang script 3x achter elkaar de data is veranderd (door een snel script), kom ik boven de 30 seconde "execution time" heen.
Hier krijgt de gebruiker een foutmelding terug. Ik verwacht dat dat binnen korte tijd heel veel zal gebeuren. Vandaar dat ik nu al een oplossing zoek.

Ik zoek eigenlijk iets in de richting van een soort wachtrij zodat elke script aan de beurt komt, zonder dat ik veel snelheid verlies.

Ik zou het niet erg vinden als elke gebruiker 10 seconden voor een pagina moet wachten.
Maar ik vind het wel erg als een gebruiker een foutmelding door een time-out krijgt.
Volgens mij moet je dan gewoon een lock gebruiken, dat is de enige manier om ervoor te zorgen dat de data niet kan worden opgehaald voor de lange berekening, als deze al door een ander wordt "gewijzigd". Ik zou dit doen door een kolom op te nemen voor elke record met een timestamp van laatste lock, wanneer een tweede script de zelfde data opvraagd checkt deze of er tussen de timestamp uit de tabel en de huidige timestamp een bepaalde marge zit, zo ja, dan update hij deze timestamp (hierbij kan je dan eventueel checken of de timestamp die je gaat updaten dezelfde is als de timestamp die je dacht te gaan updaten).... Het voordeel hiervan is dat door het onverwachts eindigen van het script de records niet gelocked blijven. Een ander voordeel is dat de wachtende scripts weten wanneer ze een retry kunnen doen aangezien ze weten wanneer de "lock" verloopt. Uiteraard moet het script dat de lock heeft geplaatst weten dat hij NA de lock-marge niet meer mag updaten!

[ Voor 8% gewijzigd door Verwijderd op 10-10-2006 14:09 ]

Pagina: 1