Avons-nous vraiment besoin de la gestion des transactions en c # ainsi que du processus de stockage de base de données des deux côtés
C #:
Using(transaction with transaction scope)
{
Execute stored proc;
Transaction. Complete;
}
Procédure stockée SQL:
Create process
As
Begin try
Begin transaction
Commit
End try
Begin catch
Rollback
End catch
First, vous devriez toujours avoir une gestion correcte des transactions dans toutes vos procédures afin que cela n'ait pas d'importance si elles sont appelées par le code de l'application, par une autre procédure, individuellement dans une requête ad-hoc, par un SQL Travail d'agent, ou tout autre moyen. Mais les instructions DML simples, ou le code qui n'apporte aucune modification, n'ont pas besoin d'une Transaction explicite. Donc, ce que je recommande, c'est:
Lorsque vous effectuez 2 instructions DML ou plus, vous avez besoin d'utiliser quelque chose dans le sens de ce qui suit (ce qui peut également être fait pour des opérations DML simples si l'on préfère pour être cohérent):
CREATE PROCEDURE [SchemaName].[ProcedureName]
(
@Param DataType
...
)
AS
SET NOCOUNT ON;
DECLARE @InNestedTransaction BIT;
BEGIN TRY
IF (@@TRANCOUNT = 0)
BEGIN
SET @InNestedTransaction = 0;
BEGIN TRAN; -- only start a transaction if not already in one
END;
ELSE
BEGIN
SET @InNestedTransaction = 1;
END;
-- { 2 or more DML statements (i.e. INSERT / UPDATE / DELETE) }
IF (@@TRANCOUNT > 0 AND @InNestedTransaction = 0)
BEGIN
COMMIT;
END;
END TRY
BEGIN CATCH
IF (@@TRANCOUNT > 0 AND @InNestedTransaction = 0)
BEGIN
ROLLBACK;
END;
DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE(),
@ErrorState INT = ERROR_STATE(),
@ErrorSeverity INT = ERROR_SEVERITY();
-- optionally concatenate ERROR_NUMBER() and/or ERROR_LINE() into @ErrorMessage
RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
RETURN;
END CATCH;
Lorsque vous effectuez une seule instruction DML ou simplement un SELECT, vous pouvez vous en sortir avec les éléments suivants:
CREATE PROCEDURE [SchemaName].[ProcedureName]
(
@Param DataType
...
)
AS
SET NOCOUNT ON;
BEGIN TRY
-- { 0 or 1 DML statements (i.e. INSERT / UPDATE / DELETE) }
END TRY
BEGIN CATCH
DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE(),
@ErrorState INT = ERROR_STATE(),
@ErrorSeverity INT = ERROR_SEVERITY();
-- optionally concatenate ERROR_NUMBER() and/or ERROR_LINE() into @ErrorMessage
RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
RETURN;
END CATCH;
Second, vous devez gérer la transaction au niveau de la couche d'application uniquement si vous devez exécuter plus d'une requête/procédure stockée et ils doivent tous être regroupés en une opération atomique. Faire un seul SqlCommand.Execute___
doit seulement être dans un try/catch, mais pas dans une transaction.
Mais, cela fait-il mal d'effectuer une transaction au niveau de la couche d'application lorsque vous effectuez un seul appel? S'il nécessite MSDTC (Microsoft Distributed Transaction Coordinator), il est un peu plus lourd sur le système de le faire au niveau de la couche d'application lorsqu'il n'est pas expressément nécessaire. Personnellement, je préfère éviter les transactions basées sur la couche d'application, sauf si cela est absolument nécessaire, car cela réduit le potentiel de transactions orphelines (si quelque chose s'est mal passé avec le code de l'application avant de faire la validation ou la restauration). J'ai également constaté que cela rend parfois le débogage de certaines situations un peu plus difficile. Mais cela étant dit, je ne vois rien techniquement mal avec aussi gérer la transaction au niveau de la couche d'application lors d'un seul appel proc ; encore une fois, une seule instruction DML est sa propre transaction et n'a pas besoin de gestion de transaction explicite sur l'une ou l'autre couche.