原文:http://www.cnblogs.com/aito/archive/2010/08/25/1808569.html

避免SQL注入的方法有两种:
一是所有的SQL语句都存放在存储过程中,这样不但可以避免SQL注入,还能提高一些性能,并且存储过程可以由专门的数据库管理员(DBA)编写和集中管理,不过这种做法有时候针对相同的几个表有不同条件的查询,SQL语句可能不同,这样就会编写大量的存储过程,所以有人提出了第二种方案:参数化SQL语句。例如我们在本篇中创建的表UserInfo中查找所有女性用户,那么通常情况下我们的SQL语句可能是这样:

1
select * from UserInfo where sex=0

在参数化SQL语句中我们将数值以参数化的形式提供,对于上面的查询,我们用参数化SQL语句表示为:

1
select * from UserInfo where sex=@sex

再对代码中对这个SQL语句中的参数进行赋值,假如我们要查找UserInfo表中所有年龄大于30岁的男性用户,这个参数化SQL语句可以这么写:

1
select * from UserInfo where sex=@sex and age>@age

下面是执行这个查询并且将查询结果集以DataTable的方式返回的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
//实例化Connection对象
SqlConnection connection = new SqlConnection("server=localhost;database=pubs;uid=sa;pwd=''");
//实例化Command对象
SqlCommand command = new SqlCommand("select * from UserInfo where sex=@sex and age>@age", connection);
//第一种添加查询参数的例子
command.Parameters.AddWithValue("@sex", true);
//第二种添加查询参数的例子
SqlParameter parameter = new SqlParameter("@age", SqlDbType.Int);//注意UserInfo表里age字段是int类型的
parameter.Value = 30;
command.Parameters.Add(parameter);//添加参数
//实例化DataAdapter
SqlDataAdapter adapter = new SqlDataAdapter(command);
DataTable data = new DataTable();

上面的代码是访问SQL Server数据库的代码。如果本文中提到的数据分别在Access、MySQL、Oracle数据库,那么对应的参数化SQL语句及参数分别如下:

数据库 Access MySQL Oracle
 SQL语句 select * from UserInfo 
where sex=? and age>?
select * from UserInfo 
where sex=?sex and age>?age
select * from UserInfo 
where sex=:sex and age>:age
参数 OleDbParameter MySqlParameter OracleParameter
实例化参数 OleDbParameter p=new OleDbParameter(“?”, OleDbType. Boolean); MySqlParameter p=new MySqlParameter(“?sex”, MySqlDbType.Bit); OracleParameter p=new OracleParameter(“:sex”, OracleType.Byte);
赋值 p.Value=true; p.Value=1; p.Value=1;

通过上面的实例代码我们可以看出尽管SQL语句大体相似,但是在不同数据库的特点,可能参数化SQL语句不同,例如在Access中参数化SQL语句是在参数直接以“?”作为参数名,在SQL Server中是参数有“@”前缀,在MySQL中是参数有“?”前缀,在Oracle中参数以“:”为前缀。 
注意:因为在Access中参数名都是“?”,所以给参数赋值一定要按照列顺序赋值,否则就有可能执行出错。

Command对象传参效率测试

在.net平台,普通的insert语句有两种写法,不带参数insert into test(c1,c2) values(var1,var2)和带参数insert into test(c1,c2) values(:c1,:c2),它们的执行效率如何呢?
做了个试验,代码如下:(数据库是oracle)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public partial class WebForm1 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //test1();
            test2();
        }
        private void test1()
        {
            OracleConnection con = new OracleConnection();
            con.ConnectionString = "Data Source=oracl;User Id=xxx;Password=xxx;Persist Security Info=True;";
            System.Random r = new Random((int)System.DateTime.Now.Ticks);
            string strCommand = "insert into test(c1,c2) values({0},{1})";
            OracleCommand com = new OracleCommand();
            com.Connection = con;
            con.Open();
            DateTime dt = DateTime.Now;
            Label1.Text = "不传参:"+DateTime.Now.ToLongTimeString();
            for (int i = 0; i < 50000; i++)
            {
 
                com.CommandText = string.Format(strCommand, r.Next(), r.Next());
                com.ExecuteNonQuery();
            }
            com.CommandText = "truncate table test";
            com.ExecuteNonQuery();
            con.Close();
            Label2.Text = DateTime.Now.ToLongTimeString();
        }
        private void test2()
        {
            OracleConnection con = new OracleConnection();
 
            con.ConnectionString = "Data Source=bocodb;User Id=hljyd;Password=hljyd;Persist Security Info=True;";
            System.Random r = new Random((int)System.DateTime.Now.Ticks);
            string strCommand = "insert into test(c1,c2) values(:c1,:c2)";
            OracleCommand com = new OracleCommand();
            com.Parameters.Add(":c1", OracleType.Number);
            com.Parameters.Add(":c2", OracleType.Number);
            com.CommandText = strCommand;
            com.Connection = con;
            con.Open();
            Label1.Text = "传参:"+DateTime.Now.ToLongTimeString();
            for (int i = 0; i < 50000; i++)
            {
                com.Parameters[":c1"].Value = r.Next();
                com.Parameters[":c2"].Value = r.Next();
                 
                com.ExecuteNonQuery();
            }
            com.Parameters.Clear();
            com.CommandText = "truncate table test";
            com.ExecuteNonQuery();
            con.Close();
            Label2.Text = DateTime.Now.ToLongTimeString();
        }
    }

执行结果:
10000记录:
不传参数?5:46:19 15:46:34 15秒
传参数:?5:50:51 15:51:01 10秒

50000记录:
不传参数  16:09:03 16:10:24 81秒
传参数::16:15:43 16:16:36 53秒
这只是2个参数的情况,如果参数很多会不会影响更大呢?

10000记录,7个参数:
不传参数:17:11:01 17:11:18 17秒
传参数:17:13:46 17:13:59 13秒
50000记录:7个参数:
不传参数:17:19:02 17:20:25 1分23秒
传参数:17:15:09 17:16:10 1分1秒

需要相差不大,但是向command对象传递参数既可以避免sql注入问题,也可以提高性能;

参数化SQL的更多相关文章

  1. SQL Server SQL性能优化之--数据库在“简单”参数化模式下,自动参数化SQL带来的问题

    数据库参数化的模式 数据库的参数化有两种方式,简单(simple)和强制(forced),默认的参数化默认是“简单”,简单模式下,如果每次发过来的SQL,除非完全一样,否则就重编译它(特殊情况会自动参 ...

  2. SQL Server中参数化SQL写法遇到parameter sniff ,导致不合理执行计划重用的一种解决方案

    parameter sniff问题是重用其他参数生成的执行计划,导致当前参数采用该执行计划非最优化的现象.想必熟悉数据的同学都应该知道,产生parameter sniff最典型的问题就是使用了参数化的 ...

  3. 多层架构(参数化SQL、存储过程)

    设置参数化SQL的方式: ------语法一 //设置SQL语句中的参数 //定义 SqlParameter parUid = new SqlParameter("@userId" ...

  4. 如何用参数化SQL语句污染你的计划缓存

    你的SQL语句的参数化总是个好想法.使用参数化SQL语句你不会污染你的计划缓存——错!!!在这篇文章里我想向你展示下用参数化SQL语句就可以污染你的计划缓存,这是非常简单的! ADO.NET-AddW ...

  5. 参数化SQL sql语句

    在日常的数据插入时,需要避免数据脚本注入攻击,所以进行参数化SQL很有必要. --说明参数 ) --参数赋值 ' --数据插入 ,'A')

  6. 在ADO.NET中使用参数化SQL语句访问不同数据库时的差异

    在ADO.NET中经常需要跟各种数据库打交道,在不实用存储过程的情况下,使用参数化SQL语句一定程度上可以防止SQL注入,同时对一些较难赋值的字段(如在SQL Server中Image字段,在Orac ...

  7. 参数化SQL小认识

    在做机房收费系统项目,编写数据连接并访问数据库时,见别人都用了带“@”字符的SQL语句,就很好奇为什么都用这个语句呢?直接拼写SQL语句不是更加方便吗?带着这个问题上网查资料,才知道原来他们用的是参数 ...

  8. 参数化SQL语句

    避免SQL注入的方法有两种:一是所有的SQL语句都存放在存储过程中,这样不但可以避免SQL注入,还能提高一些性能,并且存储过程可以由专门的数据库管理员(DBA)编写和集中管理,不过这种做法有时候针对相 ...

  9. SQL Server参数化SQL语句中的like和in查询的语法(C#)

    sql语句进行 like和in 参数化,按照正常的方式是无法实现的 我们一般的思维是: Like参数化查询:string sqlstmt = "select * from users whe ...

  10. 使用参数化SQL

    Java.C#等语言提供了参数化SQL机制,使用参数化SQL开发人员为在运行时才能确定的参数值设置占位符,在执行的时候再指定这些占位符所代表的值.示例代码如下: string user=txtUser ...

随机推荐

  1. python基础之os模块操作

    # os模块 目录相关内置库import os# . 当前目录 .. 返回上一级目录# 1. os.path.abspath() --获取当前文件的绝对路径(不包含os模块.py) pwd# path ...

  2. 关键字替代符号C++

    不知从什么时候的哪里我看到了一个and关键字,心想这是个什么玩意...然后知道它相当于&&,于是开启了罪恶的生涯-- 替代关键字,似乎可读性更好,但是有些编译器可能会无法识别(eg.M ...

  3. Bootstrap框架--DataTables列表示例--添加判断

    一.参考代码 <%@ include file="./include/header.jsp"%> <!-- jquery.dataTables.css --> ...

  4. HTMLTestRunner.py 文件,已修改完成

    """ A TestRunner for use with the Python unit testing framework. It generates a HTML ...

  5. redis的过期删除策略

    一.redis的三种过期策略 1.定时删除在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除优点:保证内存被尽快释放缺点:1)若过期key很多, ...

  6. ETL数仓测试

    前言 datalake架构 离线数据 ODS -> DW -> DM https://www.jianshu.com/p/72e395d8cb33 https://www.cnblogs. ...

  7. dio框架访问云函数参数传递问题(以腾讯云中的云函数为例子)第一部

    dd云函数其实比较普及,这里以腾讯云的云函数为例,传递参数完成简单的账号注册. 一.第一步先注册腾讯云账号,这里不过多阐述,接着点击 控制台 进入开发者界面.(注意提前进行实名认证) 二.开发者界面如 ...

  8. [JS]异步任务之事件循环

    前言 常常会听到单线程和多线程这两个名词,单线程即一个时间段内程序从上到下执行任务,多线程即一个时间段内程序同时执行多个任务. 然而 JavaScript 是单线程的,它不像 Java 那样新开启一个 ...

  9. linux之frp服务部署(内网穿透)

    frp服务部署(内网穿透) 目的 更快的进行内网穿透调试以及云端开发测试 服务器为CentOS 7,客户端为win11 frp介绍 frp 是一个开源项目, 采用 C/S 模式,将服务端部署在具有公网 ...

  10. 小程序中多个echarts折线图在同一个页面的使用

    最近做小程序的业务中遇到一个页面要同时显示几个echarts图,刚开始遇到各种冲突,死数据可以,动态数据就报错的问题,折磨了一天,仔细看了官网和查在各种资料之后,终于解决了. 直接上代码: commi ...