7
votes

Php et concurrence

Je fais des travaux de développement Web dans PHP récemment qui m'a amené à étudier sur la langue en général. Jusqu'à présent, je n'ai pas besoin de l'utiliser pour interagir avec une base de données, mais je sais qu'il fournit de nombreuses fonctions pratiques pour le faire.

Bien que je connaisse SQL de base et avoir travaillé avec la manipulation de base des données dans une base de données, je Ne comprenez pas la manière dont les développeurs Web qui basent leurs sites Web autour de PHP / JavaScript / SQL sont en mesure de gérer les utilisateurs modifiant les mêmes données en même temps.

Par exemple, disons que vous avez un site Web de blackjack qui se divise utilisateurs dans l'une des deux équipes quand ils s'inscrivent. Chaque fois qu'un utilisateur gagne un jeu, une partie de leurs gains est ajoutée à un total exécuté pour cette équipe.

SOIT SOIT DONNER LE PSUDED CODE POUR LA FONCTION QU'ECTÉE Ceci ressemble à ceci: xxx

Si deux joueurs jouent en même temps, il est très possible qu'ils appellent tous les deux sélectionnés avant que l'autre ait une chance d'incrémenter et de mettre à jour la table, de sorte que les utilisateurs changent être immédiatement écrasé.

Ma question est, comment l'évite-t-elle? Est-ce que cela soit fait en utilisant PHP au niveau du code ou existe-t-il des fonctionnalités fournies par la base de données que vous utilisez pour éviter cela?

Je fais des recherches, et il semble que PHP fournit un SEMAPHORE Mécanisme, et j'ai également remarqué que MySQL propose un Table de verrouillage Caractéristique . Cependant, je ne suis pas sûr lequel d'entre eux, si non plus, est utilisé dans la pratique.


0 commentaires

7 Réponses :


11
votes

Gardez la logique à la base de données, ces sémantiques ont généralement été résolues pour vous.

update teams
set score = score + 1
where team_id = 1


0 commentaires

1
votes

La base de données gère le verrouillage simultané et garantit que des changements sont fabriqués atomiquement. Il s'agit d'utiliser une base de données prenant en charge ACID Transactions.

Dans la plupart des cas, les changements sont suffisamment rapides que la conflit de verrouillage est minime. Mais cela peut encore arriver, vous devez donc vérifier le statut d'erreur renvoyé après avoir exécuté une requête SQL. Le mysql_query () fonction renvoie false s'il y a un problème.

Ensuite, vous devez trouver la cause (mise à jour des conflits, des autorisations insuffisantes, une erreur de syntaxe SQL, etc.) en appelant mysql_errno () . Voir http://dev.mysql.com/doc /refman/5.1/fr/error-mesages-server.html pour référence de code d'erreur MySQL.


0 commentaires

5
votes

Si votre problème du monde réel est plus grand que cet exemple simple, vous devez utiliser une transaction en conjonction avec des tables de verrouillage pour vous assurer que les utilisateurs ne vous écrasent pas.


1 commentaires

Merci à tout le monde pour plusieurs grandes réponses que j'apprends de - mais je cherchais plus quelle est la meilleure pratique dans des problèmes de concurrence plus complexes impliquant PHP, où une seule ligne de SQL n'est pas adaptée. (Désolé si mon exemple était trompeur de cela)



2
votes

Je suis d'accord avec Xepochs Répondre, n'introduisez pas les préoccupations de la concurrence à moins que vous n'ayez absolument besoin de. Pour une bonne réponse concernant différentes stratégies de verrouillage, voir ici .


0 commentaires

5
votes

Les principales bases de données sont conçues pour gérer de telles situations.

Lorsque vous utilisez MySQL, le moteur de stockage InnoDB a la fonction de verrouillage de ligne, ce qui verrouille la ligne qui est écrite. Donc, toute demande de mise à jour qui est pour la même ligne attendra jusqu'à ce que l'opération précédente de la ligne se termine.

Si vous utilisez MyISAM Storage Engine, qui verrouille toute la table lors de la mise à jour d'une ligne. Cela crée un étranglement sur le serveur lorsque plusieurs joueurs appuyent simultanément les demandes de mise à jour. Il s'agit donc de savoir quelle base de données et en particulier quel moteur de stockage vous utilisez dans le but.


1 commentaires

Les lignes à mettre à jour sont automatiquement verrouillées dans InnoDB. Si vous souhaitez verrouiller des lignes lorsque vous les lisez dans une transaction, vous pouvez utiliser SELECT ... pour mettre à jour ou sélectionner ... Verrouillage en mode Share. Pour les différences, je recommanderais cette partie du manuel de référence MySQL: dev.mysql.com/doc/refman/5.1/fr/innodb-Transaction-model.htm l



1
votes

Je ne peux pas croire qu'aucune des réponses ci-dessus souligne que vous pouvez rencontrer une faille de conception.

Oui, toutes les réponses sont correctes, MySQL peut gérer des conditions de course et un accès mutuellement exclusif aux tables.

Cependant, si vous rencontrez un problème comme celui-ci, il est probablement temps de repenser votre conception. Pourquoi ne gardez-vous pas un identifiant utilisateur pour celui qui a ajouté une partie de leurs gains? Vous pouvez alors avoir un: xxx

mais si c'était moi, je ne me dérangerais même pas. Je voudrais simplement définir_cookie (Team_Score, Team_Score + montant) et gardez tout le côté du client. Lorsque je voudrais lire le score, je tirerais une demande AJAX à lire ou à écrire sur le serveur et à mettre à jour toujours l'interface client de manière asynchrone. Puisque vous soulignez que votre développement Web est basique, je vous recommande de consulter le cadre JQuery pour une communication asynchrone client-serveur, car il s'agit de loin le moyen le plus simple d'y parvenir.

edit : et pour le problème de la mise à jour de l'interface utilisateur de chacun lorsqu'un autre joueur ajoute un montant au score, je vous suggère de regarder sackbone.js qui serre bien votre modèle de données au client des joueurs afin qu'ils reçoivent des mises à jour immédiates lorsque la Score change.


0 commentaires

0
votes

Bases de données intégrées au contrôle de la concurrence, par exemple, vous pouvez lire sur Postgres Control Concurrency Ici . Si j'ai raison, les paramètres par défaut de PGSQL sont un verrouillage optimiste et lisez l'isolation de transaction commis, ce qui signifie que chaque transaction est consciente des modifications effectuées par d'autres transactions non engagées.

En vous casse Ces paramètres sont corrects, vous pouvez donc faire simplement Mettre à jour Team1 Set Score = Score + MyTotal , et la base de données traitera bien les problèmes de concurrence.

Si vous avez un problème de sélectionner plus long - update, vous pouvez verrouiller les lignes manuellement par la première sélection avec un Sélectionner pour la mise à jour requête.

Ce sont les meilleures pratiques actuellement ...


0 commentaires