Est-ce une mise à jour atomique? Pourquoi c'est mieux

Donc, en dépit d'avoir fait ce truc de server sql pendant un certain time, je me retrouve en train de deviner moi-même sur celui-ci.

Scénario: Je veux vendre quelque chose, mais je ne veux pas le vendre trop cher. C'est la question que j'ai. (@Quantity est généralement un nombre négatif, SalesItemId est la key primaire de la table). Cela semble être une bonne solution

UPDATE SalesItem SET QtyAvailable = QtyAvailable + @Quantity WHERE SalesItemId = @Id AND QtyAvailable + @Quantity >= 0 IF @@ROWCOUNT = 0 BEGIN RAISERROR ('Cannot sell item, would sell out') END 

Est-ce que cela fera la mise à jour et où la requête dans la même transaction, empêchant ainsi d'get un QtyAvailable inférieur à zéro? Je l'aurais pensé, mais j'ai des cas où je finis par vendre plus d'articles que je devrais. J'ai toujours pensé que c'était une autre partie du système, mais tous les doigts semblent pointer vers cette requête?

Est-il préférable de faire un process en deux étapes? par exemple. Ceci (ou l'inverse de la vérification avant la mise à jour)

 BEGIN TRAN UPDATE SalesItem SET QtyAvailable = QtyAvailable + @Quantity WHERE SalesItemId = @Id IF ( SELECT QtyAvailable > FROM SalesItem where SalesItemId = @Id) < 0 BEGIN RAISERROR ('Cannot sell item, would sell out') ROLLBACK TEAN RETURN END COMMIT TRAN 

Votre instruction de mise à jour unique est une transaction atomique. Cela semble efficace et élégant en l'état. Si vous obtenez des valeurs QtyAvaliable négatives, vous devez vérifier toutes les autres instances de votre code qui modifient sa valeur.

Vous avez dit habituellement @Quantity est un nombre négatif. Assurez-vous que si vous avez des instances où vous souhaitez append une quantité positive, puis la soustraire avec une transaction de compensation que celles-ci sont effectuées set dans une transaction.

IMHO enterrer la logique métier dans la database est une erreur (laisser dans l'application – plus facile à tester, modifier, déboguer, écrire, etc, etc), mais si vous devez absolument (par exemple, il n'y a pas "app" – vous utilisez un outil qui utilise SQL pour actionner les choses, ou vous avez une situation héritée de nombreuses applications qui dépendent de la database pour faire le travail), je voudrais:

  • créer un triggersur lors de l'insertion (et de la mise à jour, de la suppression) d'un élément de campagne qui met à jour le niveau de stock du produit
  • créer une contrainte de vérification sur le produit qui nécessite que le niveau de crosse soit différent de zéro

Ensuite, l'atomicité est câblée dans l'instruction insert (ou update or delete), car les triggersurs / controls sont déclenchés dans la même transaction que l'événement qui les triggers.

En d'autres termes, avec ceci en place, il sera impossible pour toute requête de changement de données d'ordre de provoquer une situation où un niveau de stock négatif existe.