ADO .NET主要用到了:
- SqlConnection-连接数据库
- SqlCommand-执行SQL语句或者存储过程
- SqlDataReader-执行SQL语句后数据存储于该数据流中
- SqlDataAdapter-将数据存储在DataSet中
外加几个涉及到安全的类:
- SqlConnectionStringBuilder-生成连接字符串
- SqlParameter-用参数的形式组装SQL语句
具体可以查阅MSDN ADO相关页面,下面是实例:
首先创建一个测试数据库:
create database students
use students
create table stu(
id int,
name varchar(10),
sex char(2)
)
insert into stu(id, name, sex)
values(1,'小明','女')
1.连接数据库
SqlConnection用来连接数据库,这是一切的开始,主要用到两个方法
- Open()连接数据库
- Close()关闭数据库连接,这是必须的。
创建一个c#控制台程序,实例代码都会在这里面完成
引入命名空间
using System.Data.SqlClient;
连接数据库需要连接字符串,连接SQL Server的字符串一般格式为
- Data Source=计算机名或者IP地址;Initial Catalog=数据库名;User ID=登录ID;Password=密码;
在控制台程序中添加一个连接数据库的方法,并在Main中调用
static void Main(string[] args)
{
conDataBase();
Console.Read();
}
public static void conDataBase()
{
using (SqlConnection con = new SqlConnection("Data Source=你的电脑名;Initial Catalog=students;User ID=你的ID;Password=你的密码;"))
{
try
{
con.Open();
Console.Write("数据库连接成功!");
}
catch
{
Console.Write("数据库连接失败!");
}
}
}
利用using语句可以自动释放相关资源,如果不使用using需要con.Close()方法关闭连接。运行结果:
这样就成功连接到了数据库,下面便是对数据库执行操作。
2.SqlCommand && DataReader
SqlCommand一般用到下面几个方法:
命令 | 返回值 |
---|---|
ExecuteReader |
执行查询,返回一个 DataReader 对象。 |
ExecuteScalar |
执行查询,并返回由查询返回的结果集中的第一行的第一列,其他列或行将被忽略。 |
ExecuteNonQuery |
一般执行增删改语句,返回受影响行数 |
一般用到的属性有:
Connection | 获取或设置 SqlCommand 的此实例使用的 SqlConnection。 |
CommandText | 获取或设置要在数据源中执行的 Transact-SQL 语句、表名或存储过程。 |
可以直接用相关构造函数去声明一个SqlCommand类,省去了设置上面两个属性:SqlCommand("SQL语句","SqlConnection对象");
DataReader是一个只能读取且只能前进的数据流,用read()方法读取下一个数据。不能直接创建一个DataReader对象,必须通过SqlCommand的ExecuteReader方法来构建一个DataReader对象。最后也必须使用Close()关闭Reader流。
ExecuteReader实例:
添加一个方法,并在Main中调用:
public static void DataReader()
{
using (SqlConnection con = new SqlConnection("Data Source=你的电脑名;Initial Catalog=students;User ID=你的ID;Password=你的密码;"))
{
try
{
SqlCommand com = new SqlCommand("select * from stu", con);
con.Open();
SqlDataReader read = com.ExecuteReader();
while(read.Read())
{
Console.WriteLine(read["id"].ToString() + " - " + read["name"].ToString()+ " - " + read["sex"].ToString());
}
}
catch (Exception ex)
{
Console.Write(ex);
}
}
}
执行结果:
ExecuteNonQuery实例:
public static void UpDateDateBase()
{
using (SqlConnection con = new SqlConnection("Data Source=你的电脑名;Initial Catalog=students;User ID=你的ID;Password=你的密码;"))
{
try
{
con.Open();
//插入一条数据
SqlCommand com = new SqlCommand("insert into stu(id, name, sex) values(2,'小红','男')", con);
int i = com.ExecuteNonQuery();
Console.WriteLine("更新了{0}条数据",i);
//打印目前的数据
com.CommandText = "select * from stu";
SqlDataReader read = com.ExecuteReader();
while(read.Read())
{
Console.WriteLine(read["id"].ToString() + " - " + read["name"].ToString() + " - " + read["sex"].ToString());
}
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
}
}
运行结果:
ExecuteScalar 实例:
ExecuteScalat方法返回单个值,该值是一个Object类型,需要进行转换
public static void DataScalar()
{
using (SqlConnection con = new SqlConnection("Data Source=你的电脑名;Initial Catalog=students;User ID=你的ID;Password=你的密码;"))
{
try
{
SqlCommand com = new SqlCommand("select name from stu where id = 1", con);
con.Open();
string name = com.ExecuteScalar().ToString();
Console.Write(name);
}
catch (Exception ex)
{
Console.Write(ex);
}
}
}
运行结果:
3.SqlParameter
上面的实例中都是直接写死了一个SQL查询语句,实际上并不会这样用,都是接受参数去组成SQL语句的Where部分,可能有的人直接用拼接字符串的方法来组成SQL语句,不过这样做会有风险,举个例子:
public static void DataReader(string id)
{
using (SqlConnection con = new SqlConnection("Data Source=你的电脑名;Initial Catalog=students;User ID=你的ID;Password=你的密码;"))
{
try
{
SqlCommand com = new SqlCommand("select * from stu where id = " + id, con);
con.Open();
SqlDataReader read = com.ExecuteReader();
while(read.Read())
{
Console.WriteLine(read["id"].ToString() + " - " + read["name"].ToString()+ " - " + read["sex"].ToString());
}
}
catch (Exception ex)
{
Console.Write(ex);
}
}
}
将上面的例子改为接收一个id参数去查询数据库,当参数是正常填入,比如1,这个方法没有任何问题,输出:这也是我们想要的效果,不过如果在参数上动点手脚,情况就不一样了,将传入的参数改为:
DataReader("'' or 1 = 1");
执行结果:这下子我们的数据全部暴露出来了,这种方式就是SQL注入。
可疑利用SqlParameter避免这种情况,用SqlParameter改造上面的例子:
public static void DataReader(string id)
{
using (SqlConnection con = new SqlConnection("Data Source=你的电脑名;Initial Catalog=students;User ID=你的ID;Password=你的密码;"))
{
try
{
SqlCommand com = new SqlCommand("select * from stu where id = @id", con);
SqlParameter _id = new SqlParameter("@id",id);
com.Parameters.Add(_id);
/*也可以写成
com.Parameters.Add(new SqlParameter("@id", id));
*/
con.Open();
SqlDataReader read = com.ExecuteReader();
while(read.Read())
{
Console.WriteLine(read["id"].ToString() + " - " + read["name"].ToString()+ " - " + read["sex"].ToString());
}
}
catch (Exception ex)
{
Console.Write(ex);
}
}
}
这个时候参数输入'' or 1 = 1就会发生错误,从而避免了被注入攻击。
当有多个参数的时候,可以写多个com.Parameters.Add()方法或者创建Parameters数组与AddRange()方法,例:
SqlParameter[] parameter = new SqlParameter[]
{
new SqlParameter("@id", id),
new SqlParameter("@name", "小明")
};
com.Parameters.AddRange(parameter);
4.SqlDataAdapter && DataSet
SqlDataAdapter主要用来将数据填充到DataSet中
主要属性有:
SelectCommand | 获取或设置一个 TRANSACT-SQL 语句或存储的过程用于在数据源中选择记录。 |
主要方法有:
Fill(DataSet) | 在 DataSet 中添加或刷新行。 (Inherited from DbDataAdapter) |
DataSet并不单单用于存储数据库中查询出来的数据,不过这里并不讨论其它情况,就只说数据库的内容。
代码奉上:
public static void DataSet()
{
using (SqlConnection con = new SqlConnection("Data Source=你的电脑名;Initial Catalog=students;User ID=你的ID;Password=你的密码;"))
{
try
{
con.Open();
SqlCommand com = new SqlCommand("select * from stu", con);
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = com;
DataSet ds = new DataSet();
da.Fill(ds);
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
Console.WriteLine(ds.Tables[0].Rows[i]["id"].ToString() + " - " + ds.Tables[0].Rows[i]["name"].ToString() + " - " + ds.Tables[0].Rows[i]["sex"].ToString());
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
最后可以将上面的几个方法整理一下,使其成为一个类库,就可以较为方便地操作数据库。