Rollback of aborted transaction when using DTC

479 views
Skip to first unread message

Sacha Vandenbroeck

unread,
Oct 12, 2010, 11:22:56 AM10/12/10
to nhusers
Hi all,

I have the following situation: for every webservice request I start a
new
TransactionScope. Inside this transaction scope I create a session and
a
transaction. This all works well, unless the transaction is aborted.
For
instance, when there is a trigger in the database that fails, the
transaction is automatically aborted. Once the transaction is aborted
you
do no longer have to rollback the transaction. In fact, when you try
to
rollback a transaction the following exception is returned: "The
ROLLBACK
TRANSACTION request has no corresponding BEGIN TRANSACTION." (SQL
Server
2008)

Unfortunately, when the transaction is aborted, NHibernate will still
try
to rollback that transaction (resulting in the exception described
above).
It seems like NHibernate does not take the "aborted" status into
account.
Note that in my code I do not call the Rollback-method explicitly,
this
all happens in the background.

Because the rollback fails, it also seems that the TransactionScope is
not
cleaned up correctly, resulting in the following exception for some of
the
subsequent requests:
NHibernate.TransactionException: Begin failed with SQL exception ---->
System.Data.SqlClient.SqlException: New request is not allowed to
start
because it should come with valid transaction descriptor.

Is it possible to circumvent or solve this issue?

Thanks in advance!

Diego Mijelshon

unread,
Oct 12, 2010, 10:39:45 PM10/12/10
to nhu...@googlegroups.com
Code?
 
    Diego



--
You received this message because you are subscribed to the Google Groups "nhusers" group.
To post to this group, send email to nhu...@googlegroups.com.
To unsubscribe from this group, send email to nhusers+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nhusers?hl=en.


Sacha Vandenbroeck

unread,
Oct 13, 2010, 9:00:55 AM10/13/10
to nhusers
This is the simplified code of the test case I was working on:

using (var scope = new
TransactionScope(TransactionScopeOption.RequiresNew, new
TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
{
// enforce the usage of dtc
Transaction.Current.EnlistDurable(Guid.NewGuid(), new
MyDummyEnlistmentNotification(), EnlistmentOptions.None);

using (var outerSession = firstSessionFactory.OpenSession())
using (var innerSession = secondSessionFactory.OpenSession())
using (var outerTransaction = outerSession.BeginTransaction())
using (var innerTransaction = innerSession.BeginTransaction())
{
try
{
// all other code left out

innerTransaction.Commit();
outerTransaction.Commit();
scope.Complete();
}
catch (Exception)
{
// when Transaction.Current was aborted you should not call
Rolback() anymore as this call will fail
if (Transaction.Current.TransactionInformation.Status !=
TransactionStatus.Aborted)
{
innerTransaction.Rollback();
outerTransaction.Rollback();
}
}
}
}

Both sessions connect to a different database server. Once the
transaction is aborted due to an error on one of the servers,
NHibernate will still try to rollback the transactions on the server
when Dispose() is called on the TransactionScope. This results in the
exception "The ROLLBACK TRANSACTION request has no corresponding BEGIN
TRANSACTION.".

This exception is thrown inside that Dispose() method and does not
propagate to my code. But it seems that not everything is cleaned up
correctly as subsequent requests sometimes fail with the following
exception:

NHibernate.TransactionException: Begin failed with SQL exception ----
> System.Data.SqlClient.SqlException: New request is not allowed to
start because it should come with valid transaction descriptor.

Any thoughts on this problem?
> > nhusers+u...@googlegroups.com<nhusers%2Bunsu...@googlegroups.com­>
> > .

Diego Mijelshon

unread,
Oct 13, 2010, 11:33:03 AM10/13/10
to nhu...@googlegroups.com
What happens if you reduce that to:

using (var scope = new TransactionScope())
{

       using (var outerSession = firstSessionFactory.OpenSession())
       using (var innerSession = secondSessionFactory.OpenSession())
       using (var outerTransaction = outerSession.BeginTransaction())
       using (var innerTransaction = innerSession.BeginTransaction())
       {
               // all other code left out

               innerTransaction.Commit();
               outerTransaction.Commit();
               scope.Complete();
       }
}

 
    Diego


To unsubscribe from this group, send email to nhusers+u...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages