显然,ExecuteReader用于只读,ExecuteNonQuery用于事务。但由于某种原因,即使我使用ExecuteReader,我仍然可以运行write(插入,更新,删除)命令(在textbox1中键入)。我的代码有问题,还是我误解了ExecuteReader的工作方式?
//MY CODE
string sqlStatement = textbox1.Text;
System.Data.SqlClient.SqlConnectionStringBuilder builder =
new System.Data.SqlClient.SqlConnectionStringBuilder();
builder.DataSource = ActiveServer;
builder.IntegratedSecurity = true;
System.Data.SqlClient.SqlConnection Connection = new
System.Data.SqlClient.SqlConnection(builder.ConnectionString);
Connection.Open();
System.Data.SqlClient.SqlCommand command = new
System.Data.SqlClient.SqlCommand(sqlStatement, Connection);
System.Data.SqlClient.SqlDataReader reader = command.ExecuteReader();
dataGridView1.AutoGenerateColumns = true;
bindingSource1.DataSource = reader;
dataGridView1.DataSource = bindingSource1;
reader.Close();
Connection.Close();
答案 0 :(得分:6)
ExecuteReader
只返回一个可以读取SQL过程返回的行的阅读器 - 它不会阻止您在提供该结果集的过程中运行任意SQL。
执行插入/更新/删除然后立即返回结果集(因此看起来像读取的代码)可能有点奇怪(读取:代码气味),应该检查它是否可以分成不同的动作。
答案 1 :(得分:5)
虽然两者都执行sql,但ExecuteReader
记录受{4}} 记录数量时,预计ExecuteNonQuery
会返回记录。两者都不同。但内部有多么不同取决于供应商的具体实施。您可以单独使用ExecuteReader
来执行所有数据库操作,因为它只是工作(直到现在)但是由于没有记录它不是真正正确的方法 。您可以通过ExecuteNonQuery
更清楚自己的意图。
就性能而言,我认为根本不存在差异。我尝试使用SQLite
,MySqlClient
,SqlClient
,SqlServerCe
和VistaDb
,并没有看到明显的差别。他们都应该以某种方式在内部使用ExecuteReader
。
要点:
的SqlClient:
private int InternalExecuteNonQuery(DbAsyncResult result, string methodName, bool sendToPipe)
{
if (!this._activeConnection.IsContextConnection)
{
if (this.BatchRPCMode || CommandType.Text != this.CommandType || this.GetParameterCount(this._parameters) != 0)
{
Bid.Trace("<sc.SqlCommand.ExecuteNonQuery|INFO> %d#, Command executed as RPC.\n", this.ObjectID);
SqlDataReader sqlDataReader = this.RunExecuteReader(CommandBehavior.Default, RunBehavior.UntilDone, false, methodName, result);
if (sqlDataReader == null)
{
goto IL_E5;
}
sqlDataReader.Close();
goto IL_E5;
}
IL_B5:
this.RunExecuteNonQueryTds(methodName, flag);
}
else
{
this.RunExecuteNonQuerySmi(sendToPipe);
}
IL_E5:
return this._rowsAffected;
}
和
了MySqlClient:
public override int ExecuteNonQuery()
{
int records = -1;
#if !CF
// give our interceptors a shot at it first
if ( connection != null &&
connection.commandInterceptor != null &&
connection.commandInterceptor.ExecuteNonQuery(CommandText, ref records))
return records;
#endif
// ok, none of our interceptors handled this so we default
using (MySqlDataReader reader = ExecuteReader())
{
reader.Close();
return reader.RecordsAffected;
}
}
您可以看到MySqlClient
直接调用ExecuteReader
而SqlClient
仅针对特定情况。 请注意,insert
和update
很少是瓶颈(通常是select
)。
正如我所说,在ExecuteReader
的帮助下,您不会获得受影响的行数,因此请更好地使用ExecuteNonQuery
来执行查询。 ExecuteReader
更直接的替换是ExecuteScalar
,它会在第一行读取的第一列中返回数据。
要点:
的SqlClient:
override public object ExecuteScalar()
{
SqlConnection.ExecutePermission.Demand();
// Reset _pendingCancel upon entry into any Execute - used to synchronize state
// between entry into Execute* API and the thread obtaining the stateObject.
_pendingCancel = false;
SqlStatistics statistics = null;
IntPtr hscp;
Bid.ScopeEnter(out hscp, "<sc.sqlcommand.executescalar|api> %d#", ObjectID);
try
{
statistics = SqlStatistics.StartTimer(Statistics);
SqlDataReader ds = RunExecuteReader(0, RunBehavior.ReturnImmediately, true, ADP.ExecuteScalar);
object retResult = null;
try
{
if (ds.Read())
{
if (ds.FieldCount > 0)
{
retResult = ds.GetValue(0);
}
}
return retResult;
}
finally
{
// clean off the wire
ds.Close();
}
}
finally
{
SqlStatistics.StopTimer(statistics);
Bid.ScopeLeave(ref hscp);
}
}
和
了MySqlClient:
public override object ExecuteScalar()
{
lastInsertedId = -1;
object val = null;
#if !CF
// give our interceptors a shot at it first
if (connection != null &&
connection.commandInterceptor.ExecuteScalar(CommandText, ref val))
return val;
#endif
using (MySqlDataReader reader = ExecuteReader())
{
if (reader.Read())
val = reader.GetValue(0);
}
return val;
}
因此ExecuteReader
使用ExecuteScalar
并没有任何性能差异也没有什么坏处。
答案 2 :(得分:3)
这些方法的底层实现只是执行给定的SQL语句,因此您可以使用任何这些方法运行几乎任何语句。只是最终结果是读者试图返回预期的结果集,而另一种方法不期望结果集。使用ExecuteReader运行不生成结果集的语句可能效率稍低。提供程序仍然会创建一个数据读取器对象,这会增加一点成本(在大多数情况下可能忽略不计,除非提供程序最终再次向服务器进行往返调用)。