do I have to explicity dispose the transaction once I've already disposed the session?

I think that it's not necessary in this case (although I know we can use using for the transaction as well as for the session). Here is the code I'm wondering about:

using(var session = _sessionFactory.OpenSession()){
     session.BeginTransaction();
     try {
        //some code
        session.Transaction.Commit();
     } catch(Exception ex){
        session.Transaction.Rollback();
     }
}

Is there any leakage for the code above? I know it would seem to be better to write it like this:

using(var session = _sessionFactory.OpenSession()){
     using(var t = session.BeginTransaction()){
       try {
          //some code
          t.Commit();
       } catch(Exception ex){
          t.Rollback();
       }
     }
}

However as I said, I wonder about the necessity to dispose the transaction explicitly as well. Please advise. Btw do the above code is safe enough (using/closing right away) to use for polling data such as every second? Can it bombard with increasing opened connections to the target database? I don't think keeping a long-opening connection is good in any case.

1 answer

  • answered 2019-11-08 13:58 Athanasios Kataras

    Check the documentation here microsoft docs

    Calling this method marks the end of the transaction scope. If the TransactionScope object created the transaction and Complete was called on the scope, the TransactionScope object attempts to commit the transaction when this method is called. In this case, this method blocks until the first phase of transaction processing is complete. The first phase ends after all resource managers and enlistments in the transaction have voted on the transaction outcome and the TransactionManager has durably decided to commit or abort the transaction. The second phase of processing is always asynchronous. Therefore, there is no guarantee that data just committed from within a given transaction will be immediately available afterwards when not using another transaction to view this data.

    The use of the C# using construction ensures that this method is called even if an exception occurs. Exceptions that occur after calling this method may not affect the transaction. This method also restores the ambient transaction to it original state. A TransactionAbortedException is thrown if the transaction is not actually committed.

    In truth, this would be the exact same thing with having a finally clause with dispose command in it only. But you can never be sure that the next developer will not do something like this:

    using(var session = _sessionFactory.OpenSession()){
         using(var t = session.BeginTransaction()){
           try {
              //some code
              t.Commit();
           } catch(Exception ex){
              // Code the throws exception
              t.Rollback();
           } finally {
              // Some other code that throws exception
              // And then dispose
           }
         }
    }
    

    So instead of syntactic sugar, this also helps make sure that whatever happens everything is disposed correctly.

    You can check the code here https://github.com/nhibernate/nhibernate-core/blob/master/src/NHibernate/Impl/

    In SessionImpl.cs you will find that the code does nothing to close and/or dispose the transaction.