2016-04-26 1 views
2

Dans mon code .NET, dans une transaction de base de données (en utilisant TransactionScope), je pourrais inclure un bloc imbriqué avec TransactionScopeOption.Suppress, qui assure que les commandes dans le bloc imbriqué sont validées même si le bloc externe revient en arrière. Voici un exemple de code:Equivalent T-SQL de .NET TransactionScopeOption.Suppress

using (TransactionScope txnScope = new TransactionScope(TransactionScopeOption.Required)) 
{ 
    db.ExecuteNonQuery(CommandType.Text, "Insert Into Business(Value) Values('Some Value')"); 

    using (TransactionScope txnLogging = new TransactionScope(TransactionScopeOption.Suppress)) 
    { 
     db.ExecuteNonQuery(CommandType.Text, "Insert Into Logging(LogMsg) Values('Log Message')"); 
     txnLogging.Complete(); 
    } 

    // Something goes wrong here. Logging is still committed 

    txnScope.Complete(); 
} 

je tentais de trouver si cela pourrait être fait dans T-SQL. Quelques personnes ont recommandé OPENROWSET, mais il ne semble pas très «élégant» à utiliser. En outre, je pense que c'est une mauvaise idée de mettre des informations de connexion dans le code T-SQL. J'ai utilisé SQL Service Broker par le passé, mais il prend également en charge la messagerie transactionnelle, ce qui signifie que le message n'est pas publié dans la file d'attente tant que la transaction de base de données n'est pas validée.

Mon exigence: Nos procédures stockées d'application sont lancées par une application tierce, au sein d'une transaction implicite initiée en dehors de la procédure stockée. Et je veux être en mesure d'attraper et d'enregistrer toutes les erreurs (dans une table de base de données dans la même base de données) dans mes procédures stockées. Je dois relancer l'exception pour permettre à l'application tierce de restaurer la transaction et pour qu'elle sache que l'opération a échoué (et donc faire tout ce qui est requis en cas de défaillance).

+0

Votre code .NET est donc appelé par un code .NET tiers? – usr

+0

Avez-vous regardé les tables de variables? – Shaneis

+0

@usr - Je n'ai aucune connaissance du code de l'application tierce. Le code .NET que j'ai posté dans ma question était juste que je voudrais faire la même chose dans le code T-SQL. –

Répondre

4

Vous pouvez configurer un serveur lié loopback avec l'option remote proc transaction Promotion définie sur false, puis y accéder dans TSQL ou utiliser une procédure CLR dans SQL Server pour créer une nouvelle connexion en dehors de la transaction et effectuer votre travail.

Les deux méthodes proposées dans How to create an autonomous transaction in SQL Server 2008.

Les deux méthodes impliquent la création de nouvelles connexions. Il y a un open connect item demandant que cette fonctionnalité soit fournie de manière native.

+0

L'option de procédure CLR était à l'étude. Cependant, l'option de serveur lié loopback est beaucoup plus simple. Merci beaucoup! Des problèmes de performance notables de l'option de serveur lié? Cela ne va être utilisé que pour des conditions exceptionnelles (principalement dans des blocs de capture de procédures stockées). –

+0

Deux connexions au lieu d'une serait la chose principale que je peux penser, mais ne semble pas que ce sera une chose régulière. –

0

Les valeurs d'une variable de table existent au-delà d'un ROLLBACK. Ainsi, dans l'exemple suivant, toutes les lignes qui allaient être supprimées peuvent être insérées dans une table persistante et interrogées plus tard grâce à une combinaison de variables de table et de variables OUTPUT.

-- First, create our table 
CREATE TABLE [dbo].[DateTest] ([Date_Test_Id] INT IDENTITY(1, 1), [Test_Date] datetime2(3)); 

-- Populate it with 15,000,000 rows 
-- from 1st Jan 1900 to 1st Jan 2017. 
INSERT INTO [dbo].[DateTest] ([Test_Date]) 
SELECT 
TOP (15000000) 
    DATEADD(DAY, 0, ABS(CHECKSUM(NEWID())) % 42734) 
    FROM [sys].[messages] AS [m1] 
    CROSS JOIN [sys].[messages] AS [m2]; 

BEGIN TRAN; 

BEGIN TRY 

    DECLARE @logger TABLE ([Date_Test_Id] INT, [Test_Date] DATETIME); 

    -- Delete every 1000 row 
    DELETE FROM [dbo].[DateTest] 
    OUTPUT deleted.Date_Test_Id, deleted.Test_Date INTO @logger 
    WHERE [Date_Test_Id] % 1000 = 0; 

    -- Make it fail 
    SELECT 1/0 

    -- So this will never happen 
    COMMIT TRANSACTION; 

END TRY 
BEGIN CATCH 

    ROLLBACK TRAN 
    SELECT * INTO dbo.logger FROM @logger; 

END CATCH; 

SELECT * FROM dbo.logger; 

DROP TABLE dbo.logger; 
+0

La question indique que "l'application tierce" annule la transaction. Le rollback n'est pas dans le proc lui-même (bien que ce serait une meilleure solution si elle est facultative où cela se produit) –