ExecuteScalar方法返回值 及 DBnull和NUll的区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ExecuteScalar方法返回值 及 DBnull和NUll的区别相关的知识,希望对你有一定的参考价值。

参考技术A cmd.ExecuteScalar()方法返回值类型为object

当查询没有任何返回值时会返回Null,表现为直接在SQL Management Studio内查询,没有返回值,为空白。则ExecuteScalar()返回NULL值

当查询有返回值,如果第一行第一列值为NULL,表现为直接在SQL Management Studio内查询,显示为NULL,则ExecuteScalar()返回DBNull值

DBNull.ToString()为空字符串,NULL.ToString()会报异常。所以最好先对返回值 进行判断是否为空再作处理。

DBNull 和 NULL的区别

null是C#中的关键字,表示此引用不指向任何地址。

DBNull只是一个普通的类,继承自object,没添加任何方法属性,其有一个唯一的实例Value。它的存在仅仅只是为了表示从数据库读取数据时遇到的数据库中的null值。

可以用Convert.IsDBNull()方法判断是不是DBNull本回答被提问者和网友采纳

当磁盘使用率高时,使用 SqlCommand.ExecuteScalar() 从序列中选择返回 NULL

【中文标题】当磁盘使用率高时,使用 SqlCommand.ExecuteScalar() 从序列中选择返回 NULL【英文标题】:Select from sequence with SqlCommand.ExecuteScalar() returns NULL when high disk usage 【发布时间】:2018-03-16 16:07:01 【问题描述】:

我在生产环境中遇到SqlCommand.ExecuteScalar() 有时会返回NULL

我在这里遇到过很多类似的问题,最接近的一个是:SqlCommand.ExecuteScalar returns null but raw SQL does not。但给出的建议与我的情况无关。

代码示例在这里:

using (var connection = new SqlConnection(connectionString))

    connection.Open();
    using (var command = connection.CreateCommand())
    
        command.CommandText = "SELECT NEXT VALUE FOR Seq_Revision";
        command.CommandType = CommandType.Text;

        return (long)command.ExecuteScalar(); //<---ExecuteScalar() here returns NULL sometimes
    

Seq_Revision 这是简单的 MSSQL 序列,如下所示:

CREATE SEQUENCE [dbo].[Seq_Revision] 
 AS [bigint]
 START WITH 0
 INCREMENT BY 1
 MINVALUE -9223372036854775808
 MAXVALUE 9223372036854775807
 CACHE  10 
GO

而且我很确定它永远不会真正返回 NULL。


当在此代码示例中返回 NULL 时,我也观察到类似的奇怪(不可重复的行为),而我确定 存在具有此 ID 的实体:

NHibernate.ISession.Get<FooEntity>(entityId)

有趣的是,通过这种方法返回 NULL 与 SQL 节点上存在大量磁盘活动(磁盘队列长度 > ~50)的时间范围非常相关。

这可能很重要:我们使用带 2 个节点的 AlwaysON 集群,其中一个节点用于读取模式(连接字符串中的ApplicationIntent=READONLY)。

MSSQL 版本是:

Microsoft SQL Server 2014 (SP2-CU5) (KB4013098) - 12.0.5546.0 (X64) 
    Apr  3 2017 14:55:37 
    Copyright (c) Microsoft Corporation
    Enterprise Edition: Core-based Licensing (64-bit) on Windows NT 6.3 <X64> (Build 9600: )

【问题讨论】:

ExecuteScalar 返回null 表示:没有返回行。如果返回的行为空值,则为DBNull.Value。这没有回答“为什么?”,但它可能是有用的上下文 @MarcGravell,我知道。但是你相信 SELECT NEXT VALUE FOR Seq_Revision 返回 0 行吗?听起来不可能。 我不知道;这是个好问题 NEXT VALUE FOR 不支持只读数据库。请参阅docs.microsoft.com/en-us/sql/t-sql/functions/… 的限制和限制 => 从连接字符串中删除 ApplicationIntent=READONLY 您能否测试这种情况,例如if (command.GetType() == typeof(DBNull)) 或者它用InvalidCastException 捕获它,然后检查值或在Thread.Sleep(1000); 之后重试,以排除磁盘的计时问题.也是添加一些日志记录以帮助形成minimal reproducible example 的好地方,我猜它是间歇性的,并且只能在 IO 压力下重现。 【参考方案1】:

我认为问题可能与序列缓存有关。

也许有一些未处理的东西导致缓存中剩余的序列号丢失。

尝试禁用序列中的缓存:

ALTER SEQUENCE [dbo].[Seq_Revision] 
 NO CACHE
GO

或尝试使用更高的缓存值:

ALTER SEQUENCE [dbo].[Seq_Revision] 
 CACHE 100
GO

【讨论】:

谢谢,我们会试试这个理论。但这无法解释为什么我有时会从 ISession.Get(id) 获得 NULL,而我确信具有此 ID 的实体确实存在:NHibernate.ISession.Get(entityId) ISession.Get 访问数据库或会话缓存以检索实体数据。如果实体存在则返回,否则返回 NULL。这意味着如果会话缓存存在未处理的问题.. 你可以得到 NULLs

以上是关于ExecuteScalar方法返回值 及 DBnull和NUll的区别的主要内容,如果未能解决你的问题,请参考以下文章

为啥 OleDb ExecuteScalar 方法在查询 COUNT 时返回 Decimal?

ExecuteNonQuery,ExecuteReader,ExecuteScalar 区别

为啥插入成功,ExecuteScalar却返回0

Command操作数据

当磁盘使用率高时,使用 SqlCommand.ExecuteScalar() 从序列中选择返回 NULL

OracleCommand ExecuteScalar 有时返回 null