有几个SQL服务器有存储过程,例如Microsoft SQL Server或PostgreSQL。还有一些客户端对象实现了存储过程调用(TADOStoredProc
在Delphi, SqlCommand
在。net Framework等)。
我一直想问的问题是:
存储过程总是以二进制表示其参数的特别有效的方式执行,还是表示存储过程参数的超级高级对象总是转换为纯文本字符串,并且存储过程总是通过将此纯文本字符串发送到SQL服务器来执行?(让我们以一种技术为例——让它是SQL Server和ADO.NET)。
我注意到对于ADO。. NET过程的参数名没有任何意义——只有它们的创建顺序是重要的,这让我想到了一个纯文本字符串的想法。
更新@Alex k
我在。net中测试了以下代码:
CREATE PROCEDURE paramtest
@par1 nvarchar(50),
@par2 nvarchar(50),
@par3 nvarchar(50)
AS
SELECT Res = '@par1 = ' + @par1 + '; @par2 = ' + @par2 + '; @par3 = ' + @par3
RETURN 555
using System;
using System.Data.SqlClient;
using System.Data;
namespace SqlParamTest
{
class Program
{
private static void addParam(SqlCommand cmd, string parameterName, ParameterDirection direction, SqlDbType dbType, int size, object value)
{
SqlParameter par = new SqlParameter(parameterName, dbType, size);
par.Direction = direction;
par.Value = value;
cmd.Parameters.Add(par);
}
static void Main(string[] args)
{
using (SqlConnection conn = new SqlConnection(@"Data Source=localhostsqlexpress;Initial Catalog=test;Integrated Security=True"))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "paramtest";
addParam(cmd, "@par3", ParameterDirection.Input, SqlDbType.NVarChar, 50, "third");
addParam(cmd, "@par2", ParameterDirection.Input, SqlDbType.NVarChar, 50, "second");
addParam(cmd, "@par1", ParameterDirection.Input, SqlDbType.NVarChar, 50, "first");
addParam(cmd, "@Return", ParameterDirection.ReturnValue, SqlDbType.Int, 0, null);
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
if (rdr.Read()) Console.WriteLine((string)rdr["Res"]);
rdr.Close();
Console.WriteLine("Return value: {0}", cmd.Parameters["@Return"].Value);
}
Console.ReadKey();
}
}
}
,是的,它以正确的方式维护参数,但我认为,是。net为参数添加了额外的检查,因为Delphi中的以下代码:
procedure TMyClass.Test(Conn: TADOConnection);
var SP:TADOStoredProc;
begin
SP := TADOStoredProc.Create(nil);
try
SP.Connection := Conn;
SP.ProcedureName := 'paramtest';
SP.Parameters.CreateParameter('@whatthehell', ftString, pdInput, 50, 'one');
SP.Parameters.CreateParameter('@AnotherCrap', ftString, pdInput, 50, 'two');
SP.Parameters.CreateParameter('?', ftString, pdInput, 50, 'three');
SP.ExecProc;
finally
SP.Free;
end;
end;
的回报:
@par1 = one; @par2 = two; @par3 = three
并且不抱怨缺少参数。
pdReturnValue仅当该参数先于其他参数创建时才有效。
不确定您在寻找什么答案,存储过程命令文本&参数传递给驱动程序/提供程序或通过ADO本地。NET将其格式化为TDS(表格数据流)RPC(远程过程调用)消息,然后通过使用的任何网络协议传递给服务器;管道,tcp/ip等。数据以二进制流的形式发送。
如果您感兴趣,可以从Microsoft获得TDS规范。
SQLCommand
存储过程调用确实需要一个参数名,它的OleDB/ODBC只关心顺序,并使用?
作为参数占位符,而不是@NAME
。
在您的示例中,顺序是不相关的,因为您为服务器提供了正确的参数名称,所以这是发送给服务器的内容:
exec paramtest @par3=N'third',@par2=N'second',@par1=N'first'
这个信息足以让服务器找出正确的参数/顺序。
如果你改成
addParam(cmd, "@xxpar3",
addParam(cmd, "@xxpar2",
addParam(cmd, "@xxpar1",
服务器将检测到它没有名为xxxpar*
的参数,并以"missing @par1"错误失败。
如果你修改了addParam
,所以它没有设置参数名。net将创建默认值:
exec paramtest @Parameter1=N'third',@Parameter2=N'second',@Parameter3=N'first'
会导致上述错误。
如果您修改了addParam
,使其不设置参数名称,然后覆盖自动名称;
cmd.Parameters.Add(par);
par.ParameterName = "";
这是执行的内容:
exec paramtest N'third',N'second',N'first'
的
@par1 = third; @par2 = second; @par3 = first
我不知道Delphi做什么…完整版的SQL Server附带了一个名为SQL Profiler的工具,它可以显示发送到服务器实例的文本数据,这样你就可以确切地看到发生了什么。sql express使用什么分析器?