SqlCommand参数与String.Format

时间:2014-03-03 17:25:10

标签: c# sql parameters command

我一直在互联网上搜索,但我似乎无法找到解释我的问题的任何东西(可能是我没有使用正确的搜索字符串),所以我发布在这里希望有人可以帮助我。 (我的程序是使用Visual Studio 2010编写的C#)

我注意到在C#中,有多种构造SQL命令的方法。

SqlConnection connection = GetAndOpenConnection(); //function containing connection string and open connection
SqlCommand command = connection.CreateCommand();

到目前为止,我没有任何问题。我遇到的问题是CommandText。我在代码中使用了几个不同的命令(SELECT / INSERT / UPDATE / DELETE),但我们可以以SELECT为例。

//Example 1:
command.CommandText = String.Format("SELECT * FROM myTable WHERE name = '{0}'", "bob");

//Example 2:
command.CommandText = "SELECT * FROM myTable WHERE name = @myName";
command.Parameters.Add(new SqlParameter("myName", "bob"));

以上两个例子之间有什么区别? (表现明智/结构明智/等)

我问的原因是因为在同一个.cs文件中,当我使用示例2中的方法时,有时候代码正常运行而有时它没有,那么我最终会像示例1中那样创建所有内容,每次都有效。

使用这两种方法都有显着的收益/损失吗?完成这样的任务的哪种方式更合适?

其他问题

好的,所以我看到方法2是更合适的方法。

但是,如果我使用方法2则会出现问题。

我有一个循环遍历List<string> names。在循环内部,当我使用方法2并添加名称作为参数时,我得到一个错误,说该参数已经存在且无法添加。

我该如何解决这个问题?

List<string> names = new List<string> {"adam", "bob", "john"};
foreach(string name in names)
{
    command.CommandText = "SELECT * FROM myTable WHERE name = @myName";
    command.Parameters.Add(new SqlParameter("myName", name));
    reader = command.ExecuteReader();

    while(reader.Read())
    {
        //loop through each cell and print on the Console
    }
}

另外,我知道有人提到参数应该是"@myName"而不是"myName"。我记得有这个问题,因为我很困惑哪种方式使用,只能测试它。 "@myName"对我不起作用,但是"myName"是,这就是我现在仍在使用方法2的部分中的代码。我正在使用.Net 4.0,不知道如果这会产生影响。

4 个答案:

答案 0 :(得分:8)

存在防止SQL注入的参数。例如,考虑在string.Format的情况下会发生什么情况{而不是bob TextBox1.Text包含1';DROP TABLE myTable;'

如果您可以完全控制参数,则无法进行SQL注入,例如参数的字符串文字。但是,您永远不知道您的代码将来会如何变化,因此根据经验,您应始终坚持使用参数更安全的方法。

如果您遇到第二种方法的某些特殊问题 - 搜索并在此处发布,则很可能已经有了解决方案。例如,在您的代码段中,实际参数名称为@myName,带有@符号,这是应该提供给SqlParameter构造函数的内容。

更新。在您的其他问题中,问题恰好在参数命名中 - 它应该是@myName

command.Parameters.Add(new SqlParameter("@myName", name));

此外,您应该清除每次迭代的参数集合:

command.Parameters.Clear();

虽然最好在每次迭代时创建新命令以避免混乱 - 请查看this thread以获取详细信息。

答案 1 :(得分:5)

如上所述,第一个(动态)查询容易受到SQL注入攻击。此外,每次执行时都必须重新编译,这会增加执行成本(并且在编译时可能会阻塞。)

第二个(参数化)查询不容易受到SQL注入攻击。此外,它的执行计划可以缓存,这样它在第一次执行时只编译一次。至少在缓存过期或因某种原因而被刷新之前。

答案 2 :(得分:3)

方法1:易受SQL注入攻击

方法2:通过更多工作来安全地执行SQ​​L

BTW它应该是command.Parameters.Add(new SqlParameter("@myName", "bob"));

答案 3 :(得分:3)

以上所有答案都是正确的,但要回答您的修改:

在每次迭代中使用它后,您需要处理该命令:

using (var conn = new SqlConnection(connectionString)
{
    conn.open(); //You only need to open the connection once, so we do it outside the loop
    foreach (var name in names)
    {
        using (var cmd = new SqlCommand("SELECT * FROM myTable where name = @MyName", conn)
        {
            cmd.Parameters.AddWithValue("@MyName", name);
            //Do something with the command
        }
        //The command is disposed of here
    }
}
//The connection is disposed of here.