Thanks Yves for looking into this! Some comments below.

2014-04-26 22:46 GMT+02:00 <ydi...@gmail.com>:

> I have been following those issues around TransactionScope for years now,
> and I was again recently facing problems regarding TS and NH. So I decided
> to finally have a look at the NH code involved in tx management, and wrote
> some test cases to confirm some assumptions on the behavior of TS and the
> DTC. I then found your post and I'm glad you summarized the situation well.
> I agree with your 3 conclusions: unnecessary use of TxCompleted event
> handler, flushing in Prepare() is bad, and NH session still needs to enlist
> (mostly because of 2nd level cache, but not exclusively: entity locks,
> connections release (?), firing interceptors).
>
> Regarding the proposed solutions, here are some comments:
>
> - no TransactionCompleted event handler: fully agree, it is redundant with
> IEnlistmentNotification
>
> - no Flush from Prepare(): I would say no Flush() on a connection that has
> already been enlisted in the same transaction. So that leaves us with 3
> options: Flush() from Dispose when in TxScope (as you also propose),
> explicit Flush() required by app code (somehow breaks the current
> programming model), or Flush from Prepare on another, new connection. The
> latter is possible if I refer to your comment on the behavior of Prepare():
> we could enlist a new connection and flush on this one. Now the question
> is: what is really a resource manager? A DB connection, or the DB server
> engine behind it? Because in the second case, that option is not doable. A
> drawback of the third option is also that there is a great chance that the
> tx will be promoted to distributed if it wasn't already, plus we have to
> open a new connection, and both are very costly. At first sight, I would
> vote for Flush() from Dispose, with new FlushMode option, but it does not
> solve the issue for code scenario 2. That's why we should maybe consider
> flushing on another connection if possible?
>

The connection is the resource manager for this purpose (i.e. you are free
to use other connections). Flush on separate connection: I think this is a
no-go solution due to the promotion issue you mention. Possibly as an
option that can be easily activated for legacy code, to make it run stable
but less performant. Also, I wonder how database engines react if there
there has been locks taken on the first connection - will a second
connection really be able to run within the scope of those locks just
because they share the same distributed transaction? I doubt it - which
means the second connection will just cause deadlock.

Regarding when to flush: The recommendation from NH for many years have
been to always use the NH transaction even when running inside transaction
scope (indeed this is really the only truly supported scenario). Such code
works both with and without a surrounding ambient transaction. It also
means that existing code conforming to this rule doesn't rely on the flawed
flush-on-prepare behavior. Removing that feature should in general have no
effect on such code. The understanding then would be that conforming code
must EITHER use NH transaction inside session, and call its Commit()
method, OR call Flush() on the session. The latter case would resemble EF's
SaveChanges().

The point of the previous paragraph would be that adding a
FlushMode.Dispose would be a separate feature - that can be evaluated and
possibly implemented some time later, but it would not be required for an
initial fix of ambient transaction support.


- finally, if possible, I would like to make use of the occasion to make
> things clear about the usage of TxScope and explicit NH transactions. There
> has always been much confusion about their use together, and no definitive
> answer: compatible? required to use Begintx with Txscope? why? That
> confusion has moreover been exacerbated by the buggy support of TxScope in
> NH. IMHO, an application should be designed to manage transactions using a
> single, consistent API, and never mix two different tx APIs. So basically,
> I would require the NH user to make a choice: either use TxScope (with the
> appropriate TxFactory!), and then making calls to
> ISession.BeginTransaction() forbidden (throw), or use BeginTx(), with a
> txfactory that does not support TxScope, and will not enlist the session in
> any ambient transaction (leave it up to the programmer if the underlying
> ADO connection automatically enlists if there is an ambient tx, or
> throw/warning if possible).
>
>

NH-transaction inside session inside ambient transaction is a supported
scenario, and indeed the recommended way to work with System.Transactions.
If an ambient transaction is present, the NH-transaction doesn't do much -
its Commit() method will typically trigger Flush(), but it will not
actually manage a DB transaction. Benefit: Code (library) using
nh-transaction inside session should work and always use transaction WITH
OR WITHOUT an ambient transaction (application code in a higher layer can
make this choice). Drawback: It makes people confused and some people think
this means that NH doesn't support System.Transactions.


/Oskar

-- 

--- 
You received this message because you are subscribed to the Google Groups 
"nhibernate-development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to nhibernate-development+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to