使用事务处理会话时的NullReference

时间:2015-01-14 19:58:19

标签: c# postgresql nhibernate connection-pooling npgsql

通常它工作正常,但在某些情况下(我无法重现)我收到了堆栈跟踪的NullReferenceException:


   at Npgsql.NpgsqlCommand.ClearPoolAndCreateException(Exception e) in C:\projects\Npgsql2\src\Npgsql\NpgsqlCommand.cs:line 1505
   at Npgsql.NpgsqlCommand.GetReader(CommandBehavior cb) in C:\projects\Npgsql2\src\Npgsql\NpgsqlCommand.cs:line 650
   at Npgsql.NpgsqlCommand.ExecuteBlind() in C:\projects\Npgsql2\src\Npgsql\NpgsqlCommand.cs:line 499
   at Npgsql.NpgsqlTransaction.Rollback() in C:\projects\Npgsql2\src\Npgsql\NpgsqlTransaction.cs:line 185
   at Npgsql.NpgsqlTransaction.Dispose(Boolean disposing) in C:\projects\Npgsql2\src\Npgsql\NpgsqlTransaction.cs:line 141
   at NHibernate.Transaction.AdoTransaction.Dispose(Boolean isDisposing) in p:\nhibernate-core\src\NHibernate\Transaction\AdoTransaction.cs:line 368
   at NHibernate.Impl.SessionImpl.Close() in p:\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:line 380
   at NHibernate.Impl.SessionImpl.Dispose(Boolean isDisposing) in p:\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:line 1738
   at NHibernate.Impl.SessionImpl.Dispose() in p:\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:line 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中)我收到异常&#34;在获取连接时超时#34;。也许这在某种程度上是相关的。

2 个答案:

答案 0 :(得分:1)

我在2.0.14.3中看到了同样的事情。你正在运行哪个版本?那个版本的NHibernate?

查看代码,我看到了

    internal NpgsqlException ClearPoolAndCreateException(Exception e)
    {
        Connection.ClearPool();
        return new NpgsqlException(resman.GetString("Exception_ConnectionBroken"), e);
    }

2.2似乎受到同样的影响

大多数其他操作总是对Connection属性进行空检查。这可能是一个错误,但它似乎也在主分支中被大量重写。

我能找到的唯一内部实际上会在内部将连接设置为null(除非它以某种方式由NHibernate完成,但我怀疑它)将是NpgsqlCommand将被处理然后从NpgsqlDataReader读取。

编辑:

根据源代码,如果NpgsqlTransaction仍有连接且事务处于活动状态,则将在Dispose上调用Rollback。在您的情况下,Commit应该将其设置为null。您在使用块中使用session.Transaction(与存储从BeginTransaction()调用返回的引用相反的事实)可能是罪魁祸首,因为如果会话中没有事件,则调用session.Transaction会隐式创建事务。 。这可能导致提交调用实际上只是对空事务进行提交,然后将在使用BeginTransaction创建的事务上调用Dispose。

在此代码运行时,您是否有可能与会话一起使用的多线程或异步代码?

答案 1 :(得分:0)

听起来像,如果在事务中发生了一些错误,它会抛出一个异常并且会处理会话/事务。尝试...

    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;
    }