使用事务处理会话时的 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。

当此代码为 运行 时,您是否有任何可能与您的会话一起工作的多线程或异步代码?