diff --git a/src/Spring/Spring.Data.NHibernate21/Data/NHibernate/HibernateTxScopeTransactionManager.cs b/src/Spring/Spring.Data.NHibernate21/Data/NHibernate/HibernateTxScopeTransactionManager.cs index eea02dd9..56da95b9 100644 --- a/src/Spring/Spring.Data.NHibernate21/Data/NHibernate/HibernateTxScopeTransactionManager.cs +++ b/src/Spring/Spring.Data.NHibernate21/Data/NHibernate/HibernateTxScopeTransactionManager.cs @@ -977,7 +977,10 @@ namespace Spring.Data.NHibernate public void SetRollbackOnly() { - SessionHolder.RollbackOnly = true; + if (SessionHolder != null) + { + SessionHolder.RollbackOnly = true; + } if (ConnectionHolder != null) { ConnectionHolder.RollbackOnly = true; @@ -993,8 +996,8 @@ namespace Spring.Data.NHibernate { get { - return SessionHolder.RollbackOnly || - (ConnectionHolder != null && ConnectionHolder.RollbackOnly); + return ((SessionHolder != null && SessionHolder.RollbackOnly) || + (ConnectionHolder != null && ConnectionHolder.RollbackOnly)); } } } diff --git a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.cs b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.cs index 7b963665..31d2ef78 100644 --- a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.cs +++ b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.cs @@ -34,6 +34,7 @@ using Spring.Transaction; using Spring.Transaction.Support; using Spring.Transaction.Interceptor; using System.Transactions; +using System.Collections.Generic; #endregion @@ -46,26 +47,46 @@ namespace Spring.Data.NHibernate [TestFixture] public class HibernateTxScopeTransactionManagerTests { - #region Fields - private IDbProvider dbProvider; - - private IPlatformTransactionManager transactionManager; - - private IApplicationContext ctx; - #endregion - - #region Constants - /// /// The shared instance for this class (and derived classes). /// protected static readonly ILog log = - LogManager.GetLogger(typeof(TemplateTests)); + LogManager.GetLogger(typeof(HibernateTxScopeTransactionManagerTests)); - //// force Spring.Data.NHibernate to be preloaded by runtime - //private Type TLocalSessionFactoryObject = typeof(LocalSessionFactoryObject); + private IApplicationContext ctx; - #endregion + private IDbProvider dbProvider; + + private IPlatformTransactionManager transactionManager; + + [Test] + public void CanProperlyReleaseConnectionsWhenTransactionsAreRolledBack() + { + for (int i = 0; i < 200; i++) + { + try + { + DoSave(true); + } + catch (Exception) + { + } + } + } + + [Test] + [Ignore("Test harness left in place to demonstrate the leaking connection issue present in NH2.1 and later")] + public void DoesNotLeakConnection() + { + DoPreventConnectionLeaksPreventionPattern(); + } + + [Test] + [Ignore("Test harness left in place to demonstrate the leaking connection issue present in NH2.1 and later")] + public void LeaksConnection() + { + DoConnectionLeakingAntiPattern(); + } [SetUp] public void SetUp() @@ -92,14 +113,66 @@ namespace Spring.Data.NHibernate } } - private static void ExecuteSql(IDbConnection conn, string sql) + /// + /// this method will fail the test as it follows the anti-pattern of failing to use the (mandatory) NH Transaction to wrap the session call + /// + private void DoConnectionLeakingAntiPattern() { - IDbCommand cmd; - cmd = conn.CreateCommand(); - cmd.CommandText = sql; - cmd.ExecuteNonQuery(); + //this counter must be larger than the 'Max Pool Size' setting in the connection string for this test to demonstrate the issue + int counter = 200; + + for (int i = 0; i < counter; i++) + { + + using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required)) + { + using (ISession session = ((ISessionFactory)ctx["SessionFactory"]).OpenSession()) + { + IList to = session.CreateCriteria().List(); + } + + //because scope.Complete() is never called, the Transaction is rolled back and this results in the orpahned connections + } + + } + } + /// + /// this method demonstrates the proper pattern to follow w NH 2.1 and later, mandating the use of an NH transaction wrapping the session + /// + private void DoPreventConnectionLeaksPreventionPattern() + { + //this counter must be larger than the 'Max Pool Size' setting in the connection string for this test to demonstrate the issue + int counter = 200; + + for (int i = 0; i < counter; i++) + { + + using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required)) + { + using (ISession session = ((ISessionFactory)ctx["SessionFactory"]).OpenSession()) + { + using (ITransaction tx = session.BeginTransaction()) + { + try + { + IList to = session.CreateCriteria().List(); + throw new Exception("this exception simulates something going wrong!"); + + } + catch (Exception) + { + tx.Rollback(); + } + } + } + + //because scope.Complete() is never called, the Transaction is rolled back but the presence of the NH transaction and its + // associated Rollback() call will enable NH to properly release the connection + } + } + } [Transaction] private void DoSave(bool simulateException) @@ -118,22 +191,16 @@ namespace Spring.Data.NHibernate tx.Complete(); } - + } - [Test] - public void CanProperlyReleaseConnectionsWhenTransactionsAreRolledBack() + private static void ExecuteSql(IDbConnection conn, string sql) { - for (int i = 0; i < 200; i++) - { - try - { - DoSave(true); - } - catch (Exception) - { - } - } + IDbCommand cmd; + cmd = conn.CreateCommand(); + cmd.CommandText = sql; + cmd.ExecuteNonQuery(); } + } } diff --git a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.xml b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.xml index 8e82d88f..a9392ddb 100644 --- a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.xml +++ b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/HibernateTxScopeTransactionManagerTests.xml @@ -3,13 +3,12 @@ xmlns:db="http://www.springframework.net/database" xmlns:tx="http://www.springframework.net/tx"> - + - @@ -32,57 +31,5 @@ - - - - - - - - diff --git a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Spring.Data.NHibernate21.Integration.Tests.2010.csproj b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Spring.Data.NHibernate21.Integration.Tests.2010.csproj index 1b157903..5eb83fa7 100644 --- a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Spring.Data.NHibernate21.Integration.Tests.2010.csproj +++ b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Spring.Data.NHibernate21.Integration.Tests.2010.csproj @@ -25,6 +25,7 @@ TRACE;DEBUG;NET_2_0,NH_2_0,NH_2_1 prompt 4 + true pdbonly