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.