黑马程序员—ADO.Net基础
黑马程序员—ADO.Net基础
ADO.Net是.Net和数据库交互的桥梁,通过ADO.Net就能在程序中执行SQL。ADO.Net中提供了对各种不同数据库的统一操作接口。
在C#中,使用数据库,不仅可以直接在SQL Server中建立数据库,也可以通过VS自带的mdf内置文件来进行操作。
连接字符串:
程序通过连接字符串指定要连哪台服务器上的、哪个实例的哪个数据库、用什么用户名密码等。
项目内嵌mdf文件形式的连接字符串为
"Data Source = .\SQLEXPRESS;AttachDBFilename = |DataDirectory|\Database1.mdf;Integrated Security = True;User Instance = True"
。其中”.\SQLEXPRESS”表示”本机上的SQLEXPRESS实例”,如果数据库实例名不是SQLEXPRESS,则需要修改。”Database1.mdf”为mdf的文件名。
SqlConnection和SqlCommand:
ADO.Net中通过SqlConnection类创建到SQL Server的连接,SqlConeection代表一个数据库连接,如:
SqlConnection conn = new SqlConnection(@"Data Source = .\SQLEXPRESS;AttachDBFilename = |DataDirectory|\Database1.mdf;Integrated Security = True;User Instance = True")
conn.Open();
其中这么写的话还需要conn.Close();conn.Dispose();因为ADO.Net中的连接等资源都实现了IDisposable接口,都需要释放资源。
我们也可以使用using,如:
using (SqlConnection conn = new SqlConnection(@"Data Source = .\SQLEXPRESS;AttachDBFilename = |DataDirectory|\Database1.mdf;Integrated Security = True;User Instance = True"))
{
conn.Open();
}
后面就可以不用conn.Close();conn.Dispose();了,因为出了using的大括号、作用域后,就会自动关闭,这里,出了作用域后,都会判断下有没有Close,如果没有Close就会先Close再调用下Dispose;这里我们顺便说一下Close和Dispose的区别,Close只是关闭链接,以后还能打开,而Dispose是直接销毁链接,不能再次使用。
另外使用SqlConnection的时候,记得要引用程序集using System.Data.SqlClient;
现在我们就可以试着插入数据了,代码如下:
static void Main(string[] args)
{
string dataDir = AppDomain.CurrentDomain.BaseDirectory;
if (dataDir.EndsWith(@"\bin\Debug\") || dataDir.EndsWith(@"\bin\Release\"))
{
dataDir = System.IO.Directory.GetParent(dataDir).Parent.Parent.FullName;
AppDomain.CurrentDomain.SetData("DataDirectory", dataDir);
}
using (SqlConnection conn = new SqlConnection(@"Data Source = .\SQLEXPRESS;AttachDBFilename = |DataDirectory|\Database1.mdf;Integrated Security = True;User Instance = True"))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "Insert into Table1(Id,Name) values(1,’王五’')";
cmd.ExecuteNonQuery();
Console.WriteLine("插入成功");
}
}
Console.ReadKey();
}
其中SqlCommand表示向服务器提交的一个命令(SQL语句等),CommandText属性是要执行的SQL语句。
SqlCommand的ExecuteNonQuery方法:
ExecuteNonQuery方法执行非查询语句(Update、Insert、Delete等);ExecuteNonQuery返回值是执行的影响行数。
SqlCommand的ExecuteScalar方法:
SqlCommand的ExecuteScalar方法用于执行查询,并返回查询所返回的结果集中第一行的第一列,因为不能确定返回值的类型,所以返回值是object类型。
得到自动增长字段的主键值,在values关键词前加上output inserted.Id,这里Id为主键字段名。执行结果就是插入的主键值,用ExecuteScalar执行最为方便。如:
using (SqlConnection conn = new SqlConnection(@"Data Source = .\SQLEXPRESS;AttachDBFilename = |DataDirectory|\Database1.mdf;Integrated Security = True;User Instance = True"))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "Insert into DL(UserName,Password) output inserted.Id values('admin','admin')";
int Id = Convert.ToInt32(cmd.ExecuteScalar());
Console.WriteLine("插入的信息主键为{0}",Id);
}
}
SqlCommand的ExecuteReader方法:
ExecuteReader返回一个有多行的结果集。如:
using (SqlConnection conn = new SqlConnection(@"Data Source = .\SQLEXPRESS;AttachDBFilename = |DataDirectory|\Database1.mdf;Integrated Security = True;User Instance = True"))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "select * from DL";
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
string userName = reader.GetString(reader.GetOrdinal("UserName"));
Console.WriteLine(userName);
}
}
}
}
这里reader.Read()会逐行向前处理,返回bool值,到最后一行,返回false,跳出while循环。GetOrdinal方法可以根据给定列名称获得列序号。
注入漏洞与参数化查询:
如下例:
Console.WriteLine("请输入用户名:");
string userName = Console.ReadLine();
Console.WriteLine("请输入密码:");
string pwd = Console.ReadLine();
using (SqlConnection conn = new SqlConnection(@"Data Source = .\SQLEXPRESS;AttachDBFilename = |DataDirectory|\Database1.mdf;Integrated Security = True;User Instance = True"))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "select Count(*) from DL where UserName = '" + userName + "'and Password = '" + pwd + "'";
int i = Convert.ToInt32(cmd.ExecuteScalar());
if (i>0)
{
Console.WriteLine("登陆成功!");
}
else
{
Console.WriteLine("用户名或密码错误!");
}
}
}
这是一个简单的判断用户名、密码是否正确的小程序。看着没什么错误,其实存在着一个很严重的漏洞,即:当我们的用户名正确的时候,密码我们输入:任意字符串1’ or ’任意字符串2’ = ‘任意字符串2;也是会登陆成功的。这就是一个注入漏洞。
如何才能防止呢?下面,我们提供另外一种写法,以上代码只需要将cmd.CommandText = "select Count(*) from DL where UserName = '" + userName + "'and Password = '" + pwd + "'";修改为
cmd.CommandText = "select Count(*) from DL where UserName = @UserName and Password = @Password";
cmd.Parameters.Add(new SqlParameter("UserName",userName));
cmd.Parameters.Add(new SqlParameter("Password", pwd));
就可以了。