使用事务处理会话时的 NullReference
NullReference when disposing session with transaction
通常它工作正常,但在某些情况下(我无法重现)我收到带有堆栈跟踪的 NullReferenceException:
在 Npgsql.NpgsqlCommand.ClearPoolAndCreateException(例外 e)在 C:\projects\Npgsql2\src\Npgsql\NpgsqlCommand.cs:1505 行
在 Npgsql.NpgsqlCommand.GetReader(CommandBehavior cb) 在 C:\projects\Npgsql2\src\Npgsql\NpgsqlCommand.cs:line 650
在 C:\projects\Npgsql2\src\Npgsql\NpgsqlCommand.cs:499 行的 Npgsql.NpgsqlCommand.ExecuteBlind()
在 C:\projects\Npgsql2\src\Npgsql\NpgsqlTransaction.cs:185 行的 Npgsql.NpgsqlTransaction.Rollback()
在 Npgsql.NpgsqlTransaction.Dispose(布尔处理)在 C:\projects\Npgsql2\src\Npgsql\NpgsqlTransaction.cs:line 141
在 NHibernate.Transaction.AdoTransaction.Dispose(Boolean isDisposing) 在 p:\nhibernate-core\src\NHibernate\Transaction\AdoTransaction.cs:line 368
在 NHibernate.Impl.SessionImpl.Close() 中 p:\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:380 行
在 p:\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:line 1738 中的 NHibernate.Impl.SessionImpl.Dispose(Boolean isDisposing)
在 NHibernate.Impl.SessionImpl.Dispose() 中 p:\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:1709 行
public virtual IEnumerable<User.PublishedInfo> GetUsersByXP(int count)
{
using (ISession session = SessionFactory.OpenSession())
{
using (session.BeginTransaction())
{
var result = session.CreateCriteria<User>()
.SetProjection(PublishedUserProjections)
.AddOrder(Order.Desc("XP"))
.SetMaxResults(count)
.SetResultTransformer(Transformers.AliasToBean<User.PublishedInfo>())
.List<User.PublishedInfo>();
foreach (var r in result)
r.Initialize();
session.Transaction.Commit();
return result; // this line
}
}
}
这里可能有什么问题?
更新
有时在同一代码片段中(但在 BeginTransaction 中)我会收到异常 "Timeout while getting a connection"。也许这在某种程度上是相关的。
在我看来,如果事务内部发生错误,它会抛出异常并处理 session/transaction。尝试...
using (ISession session = SessionFactory.OpenSession())
{
List<User.PublishedInfo> results = null;
ITransaction transaction = null;
try
{
transaction = session.BeginTransaction();
results = session.CreateCriteria<User>()
.SetProjection(PublishedUserProjections)
.AddOrder(Order.Desc("XP"))
.SetMaxResults(count)
.SetResultTransformer(Transformers.AliasToBean<User.PublishedInfo>())
.List<User.PublishedInfo>();
foreach (var r in results)
r.Initialize();
transaction.Commit();
}
catch(Exceptionn ex)
{
if (transaction != null)
transaction.Rollback();
throw;
}
return results;
}
我在 2.0.14.3 中看到了同样的情况。你是哪个版本 运行? NHibernate 是哪个版本?
查看代码,我看到了
internal NpgsqlException ClearPoolAndCreateException(Exception e)
{
Connection.ClearPool();
return new NpgsqlException(resman.GetString("Exception_ConnectionBroken"), e);
}
2.2好像也一样
大多数其他操作总是对连接进行空检查 属性。这可能是一个错误,但它似乎也在 master 分支中被大量重写。
我能找到的唯一实际上会在内部将连接设置为 null 的来源(除非它是由 NHibernate 以某种方式完成的,但我对此表示怀疑)是 NpgsqlCommand 是否会被处理然后从 NpgsqlDataReader 中读取。
编辑:
根据消息来源,如果 NpgsqlTransaction 仍然有连接并且事务处于活动状态,则回滚将在 Dispose 上调用。在您的情况下,提交应该将其设置为空。您在 using 块中使用 session.Transaction 的事实(与存储从 BeginTransaction() 调用返回的引用相反)可能是罪魁祸首,因为如果 [=] 调用 session.Transaction 会隐式创建事务29=] 出现在您的会话中。这可能会导致提交调用实际上只是提交一个空事务,然后将对使用 BeginTransaction 创建的事务调用 Dispose。
当此代码为 运行 时,您是否有任何可能与您的会话一起工作的多线程或异步代码?
通常它工作正常,但在某些情况下(我无法重现)我收到带有堆栈跟踪的 NullReferenceException:
在 Npgsql.NpgsqlCommand.ClearPoolAndCreateException(例外 e)在 C:\projects\Npgsql2\src\Npgsql\NpgsqlCommand.cs:1505 行 在 Npgsql.NpgsqlCommand.GetReader(CommandBehavior cb) 在 C:\projects\Npgsql2\src\Npgsql\NpgsqlCommand.cs:line 650 在 C:\projects\Npgsql2\src\Npgsql\NpgsqlCommand.cs:499 行的 Npgsql.NpgsqlCommand.ExecuteBlind() 在 C:\projects\Npgsql2\src\Npgsql\NpgsqlTransaction.cs:185 行的 Npgsql.NpgsqlTransaction.Rollback() 在 Npgsql.NpgsqlTransaction.Dispose(布尔处理)在 C:\projects\Npgsql2\src\Npgsql\NpgsqlTransaction.cs:line 141 在 NHibernate.Transaction.AdoTransaction.Dispose(Boolean isDisposing) 在 p:\nhibernate-core\src\NHibernate\Transaction\AdoTransaction.cs:line 368 在 NHibernate.Impl.SessionImpl.Close() 中 p:\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:380 行 在 p:\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:line 1738 中的 NHibernate.Impl.SessionImpl.Dispose(Boolean isDisposing) 在 NHibernate.Impl.SessionImpl.Dispose() 中 p:\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:1709 行
public virtual IEnumerable<User.PublishedInfo> GetUsersByXP(int count)
{
using (ISession session = SessionFactory.OpenSession())
{
using (session.BeginTransaction())
{
var result = session.CreateCriteria<User>()
.SetProjection(PublishedUserProjections)
.AddOrder(Order.Desc("XP"))
.SetMaxResults(count)
.SetResultTransformer(Transformers.AliasToBean<User.PublishedInfo>())
.List<User.PublishedInfo>();
foreach (var r in result)
r.Initialize();
session.Transaction.Commit();
return result; // this line
}
}
}
这里可能有什么问题?
更新
有时在同一代码片段中(但在 BeginTransaction 中)我会收到异常 "Timeout while getting a connection"。也许这在某种程度上是相关的。
在我看来,如果事务内部发生错误,它会抛出异常并处理 session/transaction。尝试...
using (ISession session = SessionFactory.OpenSession())
{
List<User.PublishedInfo> results = null;
ITransaction transaction = null;
try
{
transaction = session.BeginTransaction();
results = session.CreateCriteria<User>()
.SetProjection(PublishedUserProjections)
.AddOrder(Order.Desc("XP"))
.SetMaxResults(count)
.SetResultTransformer(Transformers.AliasToBean<User.PublishedInfo>())
.List<User.PublishedInfo>();
foreach (var r in results)
r.Initialize();
transaction.Commit();
}
catch(Exceptionn ex)
{
if (transaction != null)
transaction.Rollback();
throw;
}
return results;
}
我在 2.0.14.3 中看到了同样的情况。你是哪个版本 运行? NHibernate 是哪个版本?
查看代码,我看到了
internal NpgsqlException ClearPoolAndCreateException(Exception e)
{
Connection.ClearPool();
return new NpgsqlException(resman.GetString("Exception_ConnectionBroken"), e);
}
2.2好像也一样
大多数其他操作总是对连接进行空检查 属性。这可能是一个错误,但它似乎也在 master 分支中被大量重写。
我能找到的唯一实际上会在内部将连接设置为 null 的来源(除非它是由 NHibernate 以某种方式完成的,但我对此表示怀疑)是 NpgsqlCommand 是否会被处理然后从 NpgsqlDataReader 中读取。
编辑:
根据消息来源,如果 NpgsqlTransaction 仍然有连接并且事务处于活动状态,则回滚将在 Dispose 上调用。在您的情况下,提交应该将其设置为空。您在 using 块中使用 session.Transaction 的事实(与存储从 BeginTransaction() 调用返回的引用相反)可能是罪魁祸首,因为如果 [=] 调用 session.Transaction 会隐式创建事务29=] 出现在您的会话中。这可能会导致提交调用实际上只是提交一个空事务,然后将对使用 BeginTransaction 创建的事务调用 Dispose。
当此代码为 运行 时,您是否有任何可能与您的会话一起工作的多线程或异步代码?