Je comprends comment une transaction peut être utile pour coordonner une paire de mises à jour. Ce que je ne comprends pas, c'est encapsuler des déclarations uniques dans des transactions, ce qui représente 90% de ce que j'ai jamais vu. En fait, dans le code de la vie réelle, il est plus courant dans mon expérience de trouver une série de transactions logiquement liées chacune enveloppée dans sa propre transaction, mais l'ensemble n'est pas enveloppé dans une transaction.
Dans MS-SQL, y a-t-il un avantage à encapsuler des sélections uniques, des mises à jour uniques, des insertions uniques ou des suppressions uniques dans une transaction?
Je soupçonne que c'est une programmation superstitieuse.
Ça ne fait rien. Toutes les instructions SQL individuelles (à de rares exceptions près, comme les insertions en bloc sans journal ou la table tronquée) sont automatiquement "dans une transaction", que vous le disiez explicitement ou non .. (même si elles insèrent, mettent à jour ou suppriment des millions de lignes) .
EDIT: basé sur le commentaire de @ Phillip ci-dessous ... Dans les versions actuelles de SQL Server, même les insertions en masse et la table tronquée écrivent certaines données dans le journal des transactions, mais pas autant que d'autres opérations. La distinction critique d'un point de vue transactionnel est que dans ces autres types d'opérations, les données de vos tables de base de données en cours de modification ne sont pas dans le journal dans un état qui leur permet d'être annulées.
Tout cela signifie que les modifications apportées par l'instruction aux données de la base de données sont enregistrées dans le journal des transactions afin qu'elles puissent être annulées si l'opération échoue.
La seule fonction fournie par les commandes "Commencer la transaction", "Valider la transaction" et "RollBack Transaction" est de vous permettre de mettre deux ou plusieurs instructions SQL individuelles dans la même transaction.
EDIT: (pour renforcer le commentaire des marques ...) OUI, cela pourrait être attribué à une programmation "superstitieuse", ou cela pourrait être une indication d'une incompréhension fondamentale de la nature des transactions de la base de données. Une interprétation plus charitable est qu'elle est simplement le résultat d'une application excessive de cohérence qui est inappropriée et encore un autre exemple d'euphémisme Emersons qui:
ne consistance stupide est le hobgobelin des petits esprits,
adoré par les petits hommes d'État, les philosophes et les divins
Comme l'a dit Charles Bretana, "cela ne fait rien" - rien en plus de ce qui est déjà fait.
Avez-vous déjà entendu parler des exigences "ACID" d'une base de données relationnelle? Ce "A" signifie Atomic, ce qui signifie que l'instruction fonctionne dans son intégralité ou non - et pendant l'exécution de l'instruction, non d'autres requêtes peuvent être effectuées sur les données affectées par cette requête. BEGIN TRANSACTION/COMMIT "étend" cette fonctionnalité de verrouillage au travail effectué par plusieurs instructions, mais n'ajoute rien aux instructions simples.
Cependant, le journal des transactions de la base de données est toujours écrit quand une base de données est modifiée (insérer, mettre à jour, supprimer). Ce n'est pas une option, un fait qui a tendance à irriter les gens. Oui, il y a une bizarrerie avec des insertions en masse et des modes de récupération, mais il est toujours écrit dans.
Je vais également nommer les niveaux d'isolement ici. En discuter avec cela aura un impact sur les commandes individuelles, mais cela n'entraînera toujours pas l'exécution différée d'une requête déclarée avec des transactions par rapport à une requête "autonome". (Notez qu'ils peuvent être très puissants et très dangereux avec des transactions déclarées multi-instructions.) Notez également que "nolock" ne s'applique pas aux insertions/mises à jour/supprime - ces actions nécessitent toujours des verrous.
Pour moi, encapsuler une seule instruction dans une transaction signifie que j'ai la possibilité de la restaurer si j'oublie, par exemple, une clause WHERE lors de l'exécution d'une instruction UPDATE manuelle et unique. Cela m'a sauvé plusieurs fois.
par exemple.
--------------------------------------------------------------
CREATE TABLE T1(CPK INT IDENTITY(1,1) NOT NULL, Col1 int, Col2 char(3));
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
SELECT * FROM T1
--------------------------------------------------------------
/* MISTAKE SCENARIO (run each row individually) */
--------------------------------------------------------------
BEGIN TRAN YOUR_TRANS_NAME_1; /* open a trans named YOUR_TRANS_NAME_1 */
UPDATE T1 SET COL2 = NULL; /* run some update statement */
SELECT * FROM T1; /* OOPS ... forgot the where clause */
ROLLBACK TRAN YOUR_TRANS_NAME_1; /* since it did bad things, roll it back */
SELECT * FROM T1; /* tans rolled back, data restored. */
--------------------------------------------------------------
/* NO MISTAKES SCENARIO (run each row individually) */
--------------------------------------------------------------
BEGIN TRAN YOUR_TRANS_NAME_2;
UPDATE T1 SET COL2 = 'CBA' WHERE CPK = 4; /* run some update statement */
SELECT * FROM T1; /* did it correctly this time */
COMMIT TRAN YOUR_TRANS_NAME_2 /* commit (close) the trans */
--------------------------------------------------------------
DROP TABLE T1
--------------------------------------------------------------
Une excuse possible est que cette seule instruction pourrait provoquer l'exécution d'un tas d'autres SQL via des déclencheurs, et qu'ils protègent contre quelque chose de mal là-dedans, bien que je m'attends à ce que tout SGBD ait le bon sens d'utiliser des transactions implicites dans déjà de la même manière.
L'autre chose à laquelle je peux penser est que certaines API vous permettent de désactiver la validation automatique, et le code est écrit au cas où quelqu'un le ferait.
Lorsque vous démarrez une transaction explicite et émettez un DML
, les ressources verrouillées par l'instruction restent verrouillées et les résultats de l'instruction ne sont pas visibles de l'extérieur de la transaction tant que vous ne l'avez pas validée ou annulée manuellement.
C'est ce dont vous pourriez avoir besoin ou non.
Par exemple, vous pouvez vouloir montrer des résultats préliminaires au monde extérieur tout en gardant un verrou sur eux.
Dans ce cas, vous démarrez une autre transaction qui place une demande de verrouillage avant que la première ne soit validée, évitant ainsi la condition de concurrence
Les transactions implicites sont validées ou annulées immédiatement après la fin ou l'échec de l'instruction DML
.
SQL Server possède un paramètre qui permet de désactiver la validation automatique pour une session. C'est même la valeur par défaut pour certains clients (voir https://docs.Microsoft.com/en-us/sql/t-sql/statements/set-implicit-transactions-transact-sql?view=sql-server -2017 )
En fonction d'un framework et/ou d'un client de base de données que vous utilisez, le fait de ne pas placer chaque commande individuelle dans sa propre transaction peut entraîner leur regroupement dans une transaction par défaut. Envelopper explicitement chacun d'eux dans une transaction déclare clairement l'intention et s'assure réellement que cela se passe comme prévu par le programmeur, quel que soit le paramètre de validation automatique actuel, surtout s'il n'y a pas de stratégie à l'échelle de l'entreprise sur la validation automatique.
Si les commandes begin tran/commit tran sont observées dans la base de données (selon votre commentaire ici ), il est également possible qu'un framework les génère au nom d'un programmeur sans méfiance. (Combien de développeurs inspectent de près le code SQL généré par leur framework?)
J'espère que cela est toujours d'actualité, bien que la question soit quelque peu ancienne.