Faire des transactions de base de données de prévenir des conditions de course?
Ce n'est pas tout à fait clair pour moi ce que les transactions dans les systèmes de base de données ne. Je sais qu'ils peuvent être utilisés pour la restauration d'une liste de mises à jour complètement (par exemple, déduire de l'argent sur un compte et l'ajouter à un autre), mais est-ce que tout ce qu'ils font? Plus précisément, peuvent-ils être utilisés pour prévenir des conditions de course? Par exemple:
// Java/JPA example
em.getTransaction().begin();
User u = em.find(User.class, 123);
u.credits += 10;
em.persist(u); // Note added in 2016: this line is actually not needed
em.getTransaction().commit();
(Je sais que cela pourrait être écrit comme une seule requête de mise à jour, mais ce n'est pas toujours le cas)
Est ce code protégés contre les conditions de course?
Je suis surtout intéressé à la MySQL5 + InnoDB, mais en général les réponses sont aussi les bienvenus.
- C'est un exemple de lecture-modification-écriture au cycle, et est dangereux, sauf si vous êtes en train de faire contrôle d'accès concurrentiel optimiste avec une ligne de la version colonnes ou si vous utilisez
SERIALIZABLE
isolement avec une base de données qui a un fortSERIALIZABLE
de soutien. Voir l'article que j'ai écrit sur cette récemment: blog.2ndquadrant.com/...
Vous devez vous connecter pour publier un commentaire.
TL/DR: les Transactions ne pas intrinsèquement prévenir toutes les conditions de course. Vous avez encore besoin de verrouillage, abandon-et-nouvelle tentative de manipulation, ou d'autres mesures de protection dans tous le monde réel de la base de données des implémentations. Les Transactions ne sont pas un secret de la sauce, vous pouvez ajouter à vos requêtes pour assurer la sécurité de tous les effets secondaires de la concurrence.
Isolement
Ce que vous obtenez à votre question est la je dans ACIDE - l'isolement. Le plan scolaire, une pure idée est que les transactions doivent fournir parfaite isolation, de sorte que le résultat est le même que si toutes les transactions exécutées en série. En réalité, c'est rarement le cas dans la vraie SGBDR implémentations; les capacités varient par la mise en œuvre, et les règles peuvent être affaiblis par l'utilisation d'une plus faible niveau d'isolation comme
READ COMMITTED
. Dans la pratique vous ne pouvez pas supposer que les opérations de prévenir toutes les conditions de course, même àSERIALIZABLE
isolement.Certains Sgbdr ont plus de capacités que d'autres. Par exemple, PostgreSQL 9.2 et versions plus récentes ont assez bonne
SERIALIZABLE
isolement qui détecte plus (mais pas tous) les interactions possibles entre les transactions et abandonne tout, mais le conflit transactions. De sorte qu'il peut exécuter des transactions en parallèle, en toute sécurité.Peu, le cas échéant3, les systèmes ont vraiment parfait
SERIALIZABLE
isolement qui empêche possible toutes les courses et les anomalies, y compris sur des questions comme l'escalade du verrouillage et verrouillage de la commande de blocages.Même avec un fort isolement de certains systèmes (comme PostgreSQL) pour abandonner l'contradictoires des transactions, au lieu de les attendre et de les exécuter en série. Votre application doit se rappeler ce qu'il fait et re-essayez de la transaction. Ainsi, alors que la transaction a empêché de simultanéité liées à des anomalies de la conservation de la DB, il est fait d'une manière qui n'est pas transparente pour l'application.
Atomicité
Sans doute le principal but d'une transaction de base de données est qu'il fournit pour livraison atomique. Les changements ne prendront pas effet jusqu'à ce que vous valider la transaction. Lorsque vous vous engagez, tous les changements prennent effet à l'instant même autant que des autres opérations sont concernés. Aucune transaction ne peut jamais voir juste certains des changements d'une transaction1,2. De même, si vous
ROLLBACK
, puis le néant de la transaction de modifications jamais vu par toute autre transaction; c'est comme si votre transaction n'a jamais existé.C'est le Un dans ACIDE.
Durabilité
Un autre est la durabilité - la D dans ACIDE. Il précise que lorsque vous validez une transaction, il doit vraiment être enregistré pour un stockage survivre à une faute comme une perte de puissance ou un coup de redémarrage.
Cohérence:
Voir wikipédia
Contrôle d'accès concurrentiel optimiste
Plutôt que d'utiliser le verrouillage et/ou de haut niveaux d'isolement, il est commun pour les Orm comme Hibernate, EclipseLink, etc à utiliser contrôle d'accès concurrentiel optimiste (souvent appelé "le verrouillage optimiste") afin de surmonter les limitations de la faiblesse des niveaux d'isolation tout en préservant les performances.
Un élément clé de cette approche est qu'il vous permet de durée de travail à travers de multiples transactions, ce qui est un gros plus avec des systèmes qui ont une forte comptes utilisateurs et peuvent avoir de longs délais entre les interactions avec un utilisateur donné.
Références
Outre le texte des liens, voir la documentation PostgreSQL chapitre sur le verrouillage, l'isolement et de la concurrence. Même si vous utilisez un autre SGBDR vous allez apprendre beaucoup des concepts qu'il explique.
1je suis ignorant la est rarement mise en œuvre
READ UNCOMMITTED
niveau d'isolement ici pour plus de simplicité; il est permis à des lectures incorrectes.2Comme @meriton points, le corollaire n'est pas nécessairement vrai. Lectures fantômes se produire dans n'importe quoi en dessous de
SERIALIZABLE
. Une partie de l'en-cours de transaction ne pas voir certains changements (par un pas-encore-transaction validée), puis la prochaine partie de l'en-cours de transaction ne voir les modifications lors de la transaction s'engage.3 et Bien, autant que je me souvienne SQLite2 n'en vertu de verrouillage de l'ensemble de la base de données lorsqu'une écriture est tenté, mais ce n'est pas ce que j'appellerais une solution idéale aux problèmes de concurrence.
Serializable
.READ UNCOMMITTED
.Le niveau de base de données prend en charge l'atomicité des transactions, à des degrés divers, appelés niveaux d'isolation. Consultez la documentation de votre base de données pour la gestion des niveaux d'isolation de la prise en charge, et leurs compromis. Le plus fort niveau d'isolation, Serializable, nécessite des transactions à exécuter comme si elles étaient exécutées une par une. C'est généralement mis en œuvre en utilisant les verrous exclusifs dans la base de données. Cela peut provoquer des blocages, dont la base de données système de gestion de la détecte et corrige par la restauration de certains portent sur des opérations. Cette approche est souvent désigné comme le verrouillage pessimiste.
De nombreux cartographes objet-relationnels (y compris JPA fournisseurs) soutiennent également verrouillage optimiste, où les conflits de mise à jour ne sont pas empêchés dans la base de données, mais détectée dans la couche application, ce qui annule l'opération. Si vous avez activé le verrouillage optimiste, typique de l'exécution de votre exemple de code d'émettre les requêtes sql suivantes:
Disons que cela renvoie (123, 13, 100).
La base de données indique le nombre de lignes où mis à jour. Si c'en était une, il n'y a aucun conflit de mise à jour. Si c'était zéro, un conflit de mise à jour s'est produite, et le fournisseur JPA va faire
et de lever une exception si le code de l'application peut gérer la transaction qui a échoué, par exemple, une nouvelle tentative.
Résumé: Avec l'une ou l'autre approche, votre déclaration peut être faite à l'abri de conditions de course.
SERIALIZABLE
, pasSERIALIZED
. Vous dites que "Ceci est mis en œuvre en utilisant les verrous exclusifs dans la base de données", mais cela dépend de la base de données du système et de la version. PostgreSQL est capable de simultanéité dansSERIALIZABLE
isolement par la détection de la transaction, les dépendances et l'abandon de transactions qui peuvent être en conflit.Il dépend de l'isolation (en sérialisable, il va empêcher condition de course, comme généralement dans le niveau d'isolation serializable les transactions sont traitées dans l'ordre, pas en parallèle (ou au moins de verrouillage exclusif est utilisé, de sorte que les transactions, qui modifient les mêmes lignes, sont exécutés dans l'ordre).
Afin de prévenir la condition de la course, mieux verrouiller manuellement l'enregistrement (mysql par exemple il permet de " sélectionner ... pour la mise à jour de la déclaration, qui acquiert en écriture verrouillage sur les enregistrements sélectionnés)
SERIALZABLE
les transactions doivent être traitées par le SGBD de telle manière que ils auraient le même effet si le traitement en série. Ils peuvent être parallèles, aussi longtemps que le SGBD répond à cette condition, et certains systèmes (par exemple, PostgreSQL) de le faire.Dépend du sgbd. En général, les opérations d'acquisition de verrous comme décidé lors de la requête plan d'évaluation. Certains peuvent demander des verrous de table, d'autres au niveau des colonnes, d'autres niveau record, la deuxième est préféré pour la performance. La réponse courte à votre question est oui.
En d'autres termes, une opération est effectuée afin de regrouper un ensemble de requêtes et de les représenter comme une opération atomique. Si l'opération échoue, les changements sont rolledback. Je ne sais pas exactement ce que la carte que vous utilisez n', mais si elle est conforme à la définition de transactions que vous devriez être bien.
Tout ce qui garantit la prévention des conditions de course, il n'a pas explicitement à prévenir la famine ou de blocages. Le verrou de transaction manager est en charge de cela. Les verrous de Table sont parfois utilisés, mais ils viennent avec un prix lourd de réduire le nombre d'opérations simultanées.