Problèmes avec TransactionScope et Oracle
nous avons écrit en C# 3.5 client de parler à une base de données Oracle (11g) à l'aide de la ODP.NET.
Cette application dispose d'un processus de traitement par lots où une longue tâche en cours d'exécution est effectué divers appels à la base de données au sein d'une TransactionScope.
Sur notre environnement de développement tout va bien, mais à l'UAT de l'environnement de l'un de nos clients (qui a des charges de données), deux en alternance (parfois l'un, parfois l'autre...) des erreurs se produisent:
- Incapable de s'engager dans une transaction distribuée
- La transaction a été annulée. (exception interne: Délai d'expiration de Transaction)
Nous utilisons actuellement un délai de un jour pour l'opération (à des fins de test).
L'exécution dudit procédé sur l'UAT l'environnement est la cause d'arrêter après approx. 10 minutes avec l'une des exceptions ci-dessus, donc aucun moyen, près de la valeur de délai d'expiration.
Voici un extrait de la stacktrace pour la deuxième erreur:
at System.Transactions.TransactionStatePromotedAborted.CreateAbortingClone(InternalTransaction tx)
at System.Transactions.DependentTransaction..ctor(IsolationLevel isoLevel, InternalTransaction internalTransaction, Boolean blocking)
at System.Transactions.Transaction.DependentClone(DependentCloneOption cloneOption)
at System.Transactions.TransactionScope.SetCurrent(Transaction newCurrent)
at System.Transactions.TransactionScope.PushScope()
at System.Transactions.TransactionScope..ctor(TransactionScopeOption scopeOption)
at System.Transactions.TransactionScope..ctor()
at Application.Domain.DataAccess.Oracle.EntityDaoBase`2.SaveItem(TEntity item, EntityReference`1 user)
Le processus tente d'enregistrer un élément de la DB à l'intérieur de l'étendue de la transaction, mais la stacktrace montre que le constructeur est frappé pour la classe TransactionScope en ce sens qu'elle crée un nouveau TransactionScope.
Suis-je droit?
Parce que je ne connais pas trop les rouages de la TransactionScope, mais il semble que lorsque vous appelez une méthode dans le champ d'application, il va créer une nouvelle transaction (assumingly héritant de la température ambiante de la transaction).
Pourrait-il être que si je ne me trompe, que cette nouvelle transaction n'hérite pas de la corriger délai d'attente (mais celui par défaut), de sorte qu'une transaction imbriquée sera la cause de cette exception délai?
Si pas, des idées sur ce que ça peut être? Sur une note de côté, il n'y a pas de transactions imbriquées définis dans les méthodes appelé à partir de la température ambiante de la transaction.
Toute aide serait grandement appréciée!
Edit 1:
Simplifié extrait de code de la fonction:
public void SomeLengthyBatchProcess()
{
using (var transaction = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(1, 0, 0, 0)))
{
foreach (var item in Items)
{
SaveItemToDB(item);
}
transaction.Complete();
}
}
public void SaveItemToDB(object item)
{
using (var transaction = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(1, 0, 0, 0)))
{
//Performing data persistency here
transaction.Complete();
}
}
Edit 2:
Ok, donc comme il s'avère, il y est une transaction imbriquée se passe dans la méthode 'SaveItemToDB'. Après quelques recherches dans le code d'un collègue, j'ai vu qu'elle a son propre TransactionScope défini, mais sans les options de délai d'attente et de.
Après la modification de cette méthode, de sorte qu'il a les mêmes paramètres concernant le délai d'attente, j'ai couru de nouveau le code sur le serveur du client et toujours pas de chance (encore une fois la transaction avortée d'erreur avec le temps).
Donc mes questions sont désormais comme suit:
- Est-il nécessaire de définir des valeurs de délai d'expiration pour les transactions imbriquées, ou font-ils héritent de ce à partir de la température ambiante de la transaction?
- Comment est-il possible qu'un délai d'attente d'exception peut se produire lorsque le paramètre de délai d'expiration est (sans doute, en dehors de fonctionnement interne que je ne sais pas), la même pour toutes les opérations étendues et a une valeur de délai d'expiration définie de 1 jour, lorsque l'exception se produit après environ. 10 minutes?
- Est-il possible de prévenir l'Oracle de la création d'une transaction distribuée pour les transactions où la connectionstring est le même?
- Peut-il que la charge supplémentaire d'une transaction distribuée causes des exceptions comme la transaction avortée?
J'ai mis à jour l'extrait de code de sorte qu'il reflète mieux la situation.
(btw: la deuxième, la transaction imbriquée, est nécessaire parce que le DAL aussi séparément persiste quelques éléments enfant, s'il est présent, et l'ensemble des éléments doit, bien sûr, être annulée si quelque chose va mal alors que la persistance de l'enfant les éléments)
J'espère que cette outre, il sera plus facile de faire la lumière sur cette question!
OriginalL'auteur Mace | 2010-07-14
Vous devez vous connecter pour publier un commentaire.
Parce que nous ne pouvions pas trouver une solution, nous avons décidé d'arrêter d'utiliser le TransactionScope pour nos besoins et organiser la restauration de nous-mêmes.
Je trouve que TransactionScope et Oracle ne se mélangent pas bien, peut-être, SQL Server gère mieux, mais ce n'est pas une option pour nous.
Merci pour la lecture.
OriginalL'auteur Mace
la valeur par défaut délai d'expiration de transaction dans la machine.la config est à 10 minutes...c'est probablement la raison pour laquelle vous êtes à l'expiration du délai.
OriginalL'auteur gjax
Est-il possible pour vous de s'il vous plaît montrer un bout de code? À partir de ce que vous avez mentionné La seule chose que j'ai pu trouver était liée avec le Système.Des Transactions. La discussion est ici. Bien sûr, leur "solution" est de vous assurer que vous utilisez au moins ODP.NET 11.1.0.6.20 ou plus.
J'ai mis à jour l'article, semble être quelque chose d'autre se passe ici...
OriginalL'auteur mcauthorn
Je sais que c'est une vieille question, mais je vais ajouter que depuis que j'ai vu un peu les choses.
Êtes-vous à l'aide de RAC? Avez-vous travaillé avec un DBA pour voir si vous êtes en train de vivre, que le verrouillage et de blocage. J'ai utilisé le Système.Transactions avec Oracle depuis des années et la seule fois où j'ai eu des problèmes similaires, c'est quand nous avons été à l'aide de RAC et de configuration supplémentaires à faire.
Voici ce qui arrive: on démarre une transaction et de l'ouverture des connexions au cours de la transaction (ce qui est très bien). Toutefois, le service oracle n'est pas configuré pour le traitement des transactions distribuées (c'est une simple case à cocher de l'option sur le service). De nouvelles connexions couvrant plus d'une instance en cluster RAC, et des opérations connexes sont pas conscients de chaque autres provoquant l' .net de processus de bloc lui-même.
C'est une solution simple. L'oracle de service que vous utilisez juste besoin de PAO activé.
OriginalL'auteur b_levitt
bien qu'une vieille question, je suis en espérant que cette réponse vous aide...
cela se passe surtout pour un long transactions en cours d'exécution parce que le sous-jacent IDbConnection ne reste pas ouverte pour une durée plus longue et une nouvelle connexion est créé pour les pièces de transactionscope (regroupement de connexion). c'est pour la même raison, le long de la transaction pourrait réussir que si la même connexion ouverte est retourné et utilisé le reste échoue. Seule solution pour cela est de contrôler la création de la connexion et de s'assurer qu'une seule connexion est utilisé tout au long.
OriginalL'auteur Krishna Desiraju
S'attaquer à la principale question première:
Il est le
TransactionManager.MaximumTimeout
de la propriété qui est la la limite supérieure de l' de ce que vous essayez de régler via votre portée. Sur votre système, il est mis à10 minutes
, mais selon la la documentationComme pour les autres questions:
La portée initier une transaction (c'est à dire un
RequiresNew
portée, tout ultrapériphériquesRequired
portée, et toutes lesRequired
portée qui a unSuppress
champ d'application d'un niveau de nidification de la pile) établira untransaction timeout
, et dans la mesure de ma lecture de les sources va, ce délai d'attente n'est pas affecté par des étendues de.Cependant, tous imbriqués portée participant à une transaction existante (c'est à dire un
Required
portée qui a unRequired
ouRequiresNew
portée d'un niveau dans la pile) mettra en place son propre champ timeout qui s'exécute en outre les délai d'expiration de transaction mentionnés ci-dessus.Transaction délais d'attente et portée délais d'attente sont mis en œuvre différemment en interne, mais si l'un de ces délais d'attente hits, une opération encore être
Complete()
d sera annulée.Btw, précité
TransactionManager.MaximumTimeout
s'applique uniquement aux transaction délais d'attente. Portée délais d'attente n'ont pas de limite supérieure. Non pas que cela importe vraiment, le plus court délai d'attente est ce qui compte de toute façon.Aussi longtemps que vous avez seulement un "physique" DB connexion ouverte à tout point unique dans le temps, le champ ne sera pas remonter à la DTC. Si je me souviens bien, cela fonctionne avec Oracle ODP.Net malgré (cette) apparemment en prétendant le contraire (peut-être qu'il ne fonctionne pas avec la version à l'époque?).
Vous peut ou peut ne pas être en mesure d'empêcher les connexions simultanées même avec imbriqué étendues, et pour différentes bases de données (tant qu'ils sont sur le même serveur).
OriginalL'auteur Eugene Beresovsky