我一直在互联网上搜索,但我似乎无法找到解释我的问题的任何东西(可能是我没有使用正确的搜索字符串),所以我发布在这里希望有人可以帮助我。 (我的程序是使用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,不知道如果这会产生影响。
答案 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:通过更多工作来安全地执行SQL
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.