1. 数据库连接技术
ODBC -->OLeDB --> ADO.NET 我们程序与数据库互联的技术的发展
ADO.NET(Microsoft ActiveX Data Object)
C#与数据库互联的技术,就是一系列的类库,或一堆dll
Connection对象 --连接用的
Command对象 --执行用的
ExecuteNonQuery --执行的是增删改,则返回受影响的行数;否则返回-1
ExecuteScalar --返回第一行第一列的object --聚集函数
在许多情况下,需要从sQL语句返回一个结果,如给定表中的记录个数,或者服务器上的当前日期/时间
ExecuteScalar()方法就可以用于这些场合
ExecuteReader --返回多行多列
DataReader对象 --读取数据
SqlDataReader reader = cmd.ExecuteReader();
DataAdapter对象 --将上面三个对象进行封装后得到的一个对象
服务器上的sql server格式的数据文件 -- 通过转换器 -- 转换成C#可以操作的数据文件DataSet
DataSet是一个基于内存的“数据库”
using System.Data --与数据和数据类型有关的
using System.Data.Common --各个数据提供程序共享(或重写)类
using System.Data.SqlClient --专门处理sql server的
2. 第一个模型,执行非查询语句(除了查询以外的语句)
如果执行的是增删改,则返回受影响的行数;否则返回-1
int count;
using(Sqlconnection conn = new Sqlconnection(连接字符串)) //1. 创建连接对象
{
using(Sqlcommand cmd = new Sqlcommand(sql语句,conn)) //2. 创建执行对象
{
//处理参数
conn.open(); //3. 打开连接
//充分利用连接池,只放进行数据处理的代码
count = cmd.ExecuteNonQuery(); //4. 执行方法得到结果
console.Writeling("{0}行受影响", count)
}
}
3. sql注入漏洞
pwd = '1' or '1' = '1' 在密码框中输入的是:1' or '1' = '1
产生注入漏洞的直接原因就是密码框中的值输入格式没有约束,要保证只是一个值
有两种解决方法
一是将用户输入的单引号 replace("/'","/'/'")成两个单引号
二是进行参数化查询
本质-- 将需要由用户输入的数据打包成一个"变量"
步骤
1)将SQL语句中需要使用用户输入数据的地方用"@名字"的方法定义一个"变量"
"select count(*) from LoginTbl where uid = @jiang and pwd = @kun;"
2)为变量赋值
Sqlparameter p = new Sqlparameter("@变量名",数据值);
3)将参数绑定到Command对象中
cmd.Parameters.add(p);
收费版SQL Server有一个工具 SQL Server Profiler
具有监视SQL语句执行过程的功能
exec sp_executesql N '字符串' 就可以执行字符串所表达的sql语句了
4. Dispose --释放非托管资源(不由.net framework控制的)
类 val = new 类();
...
val.dispose(); --总是会忘记
使用using(){} --离开using程序块,就会释放资源,避免忘记问题
具体是实现了IDisposable接口,会执行dispose{}方法
5. 连接池
创建连接对象后,使用完,执行close()和dispose()后不会直接销毁
实际上,在执行完close()方法后,会将这些连接数据库所用的非托管资源放到一个“数组”中(字符串连接池)
若再次创建连接对象,则会首先检查连接池中是否包含连接对象,如果包含就直接拿来使用
6. 在程序设计中,要时刻关注并发的问题;
计算机是并行执行的,所以什么时候切换来执行某个应用程序是不确定的,
即便你前面进行了很多的判断,但是在你连接数据库的时候刚好切换过来,而此时别人已经把数据库修改了,
你前面的所有判断并没有起到作用 所以要用try-catch
7. ExecuteReader对象 和 SqlDataReader -->读取数据使用的
在windows 64位机上,SQL Server旗舰版不约束内存的大小,数据放在内存中读取的速度要比硬盘读取速度快的多
8. ExecuteReader对象
using(SqlDataReader reader = cmd.ExecuteReader()) //在数据库中读取数据,并将结果的部分数据放在内存池中,
//并封装一个可以读取数据的指针对象(sqlDateReader)返回
while(reader.read()){
//每次read一下,读取一条记录;
//如果没有记录返回false表示读取结束
//如果有数据,就返回true,读取该行数据的每一列
List<string> list = new List<string>();
for(int i = 0; i<read.FieldCount; i++){
list.Add(reader[i].toString());
}
//输出为.csv文件
File.AppendAllText("top10.csv",string.join(",",list)+"\r\n",Encoding.Default);
}
reader有一个HasRows属性: 用于判断数据已经得到,但是不用取出来,
而是将这个对象传递给别的数据处理程序进行操作的情况
reader还有一系列的get方法,getString getBoolean...
几个特殊的get方法
reader.getName(i) -- 获取列名
9. 可空类型
(数据库中的数据是可以为空的 如int类型的列是可以为空) 那么在使用reader时要注意空类型的处理
Nullable<int> num; //可空的整数类型
//可以模拟任何一种值类型,在使用上与正常的值类型完全一样
num = 10;
Nullable num有属性HasValue 如果为空 -- false 值 -- true
int n = num.HasValue? num.Value: 0;
简写形式 int n = num?? 0;
//第一种处理为空的方法 3代表第三列
DateTime dt1 = reader.IsDBNull(3)?DateTime.MinValue : reader.getDateTime(3);
判断是否是数据库中的空,如果是空,就代表是非正常时间;如果不为空,采用get系方法
//第二种处理为空的方法
Nullable<DateTime> dt2 = reader.IsDBNull(3)? null:(Nullable<DateTime>)reader.getDateTime(3);
DateTime? dt3 = reader.IsDBNull(3)? null:(DateTime?)reader.getDateTime(3);
字符串的空 和 数据库中的数据为空 是两个概念
字符串的空:IsNullOrEmpty
数据库中的空:DBNull
10. 如果一次想执行两个sql语句,可以使用reader.nextResult遍历所有结果
可以利用一个cmd对象进行sql语句的切换,如
SqlCommand cmd = new SqlCommand{
cmd.CommandText = sql; //sql语句
cmd.connection = conn; //连接对象
}
11. 案例:
1)从SQL Server中导出XML文件
2)将XML文件解析并导入SQL Server中
第一种方法
foreach (XElement e in xDoc.Root.Elements())
{
//每一个e就是一行数据
new SqlParameter("@name",e.Element("name").Value),
string.IsNullOrEmpty(e.Element("name").Value)? DBNull.Value:(object)e.Element("name").Value;
}
第二种方法
foreach (XElement e in xDoc.Descendants().Where(e=>e.Name == "stu"))
{}
12. DataSet类
数据库 DataSet
架构 命名空间
表 DataTable
列或者字段 DataColumn
行 DataRow
约束 属性
在.NET Framework3.5以后基本就不使用DataSet了--使用泛型
第一行(包含字段,字段有类型)就相当于一个类,每条记录就是对象,一张表就相当于一个集合
DataSet ds = new DataSet();
using(SqlDataAdapter sda = new SqlDataAdapter(sql,connStr))
{
sda.Fill(ds);
}
13. 数据库配置文件
应用程序配置文件App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="connStr01" connectionString="server=.;database=MyTestDB;uid=sa;pwd=123;"/>
<add name="connStr02" connectionString="server=.;database=MyTestDB;uid=sa;pwd=123;"/>
<add name="connStr03" connectionString="server=.;database=MyTestDB;uid=sa;pwd=123;"/>
</connectionStrings>
</configuration>
为了使用ConfigurationManager类,先要在引用中添加System.Configuration
//使用ConfigurationManager类获得在App.config文件中的连接字符串
string connStr = ConfigurationManager.ConnectionStrings[name].ConnectionString;
ODBC -->OLeDB --> ADO.NET 我们程序与数据库互联的技术的发展
ADO.NET(Microsoft ActiveX Data Object)
C#与数据库互联的技术,就是一系列的类库,或一堆dll
Connection对象 --连接用的
Command对象 --执行用的
ExecuteNonQuery --执行的是增删改,则返回受影响的行数;否则返回-1
ExecuteScalar --返回第一行第一列的object --聚集函数
在许多情况下,需要从sQL语句返回一个结果,如给定表中的记录个数,或者服务器上的当前日期/时间
ExecuteScalar()方法就可以用于这些场合
ExecuteReader --返回多行多列
DataReader对象 --读取数据
SqlDataReader reader = cmd.ExecuteReader();
DataAdapter对象 --将上面三个对象进行封装后得到的一个对象
服务器上的sql server格式的数据文件 -- 通过转换器 -- 转换成C#可以操作的数据文件DataSet
DataSet是一个基于内存的“数据库”
using System.Data --与数据和数据类型有关的
using System.Data.Common --各个数据提供程序共享(或重写)类
using System.Data.SqlClient --专门处理sql server的
2. 第一个模型,执行非查询语句(除了查询以外的语句)
如果执行的是增删改,则返回受影响的行数;否则返回-1
int count;
using(Sqlconnection conn = new Sqlconnection(连接字符串)) //1. 创建连接对象
{
using(Sqlcommand cmd = new Sqlcommand(sql语句,conn)) //2. 创建执行对象
{
//处理参数
conn.open(); //3. 打开连接
//充分利用连接池,只放进行数据处理的代码
count = cmd.ExecuteNonQuery(); //4. 执行方法得到结果
console.Writeling("{0}行受影响", count)
}
}
3. sql注入漏洞
pwd = '1' or '1' = '1' 在密码框中输入的是:1' or '1' = '1
产生注入漏洞的直接原因就是密码框中的值输入格式没有约束,要保证只是一个值
有两种解决方法
一是将用户输入的单引号 replace("/'","/'/'")成两个单引号
二是进行参数化查询
本质-- 将需要由用户输入的数据打包成一个"变量"
步骤
1)将SQL语句中需要使用用户输入数据的地方用"@名字"的方法定义一个"变量"
"select count(*) from LoginTbl where uid = @jiang and pwd = @kun;"
2)为变量赋值
Sqlparameter p = new Sqlparameter("@变量名",数据值);
3)将参数绑定到Command对象中
cmd.Parameters.add(p);
收费版SQL Server有一个工具 SQL Server Profiler
具有监视SQL语句执行过程的功能
exec sp_executesql N '字符串' 就可以执行字符串所表达的sql语句了
4. Dispose --释放非托管资源(不由.net framework控制的)
类 val = new 类();
...
val.dispose(); --总是会忘记
使用using(){} --离开using程序块,就会释放资源,避免忘记问题
具体是实现了IDisposable接口,会执行dispose{}方法
5. 连接池
创建连接对象后,使用完,执行close()和dispose()后不会直接销毁
实际上,在执行完close()方法后,会将这些连接数据库所用的非托管资源放到一个“数组”中(字符串连接池)
若再次创建连接对象,则会首先检查连接池中是否包含连接对象,如果包含就直接拿来使用
6. 在程序设计中,要时刻关注并发的问题;
计算机是并行执行的,所以什么时候切换来执行某个应用程序是不确定的,
即便你前面进行了很多的判断,但是在你连接数据库的时候刚好切换过来,而此时别人已经把数据库修改了,
你前面的所有判断并没有起到作用 所以要用try-catch
7. ExecuteReader对象 和 SqlDataReader -->读取数据使用的
在windows 64位机上,SQL Server旗舰版不约束内存的大小,数据放在内存中读取的速度要比硬盘读取速度快的多
8. ExecuteReader对象
using(SqlDataReader reader = cmd.ExecuteReader()) //在数据库中读取数据,并将结果的部分数据放在内存池中,
//并封装一个可以读取数据的指针对象(sqlDateReader)返回
while(reader.read()){
//每次read一下,读取一条记录;
//如果没有记录返回false表示读取结束
//如果有数据,就返回true,读取该行数据的每一列
List<string> list = new List<string>();
for(int i = 0; i<read.FieldCount; i++){
list.Add(reader[i].toString());
}
//输出为.csv文件
File.AppendAllText("top10.csv",string.join(",",list)+"\r\n",Encoding.Default);
}
reader有一个HasRows属性: 用于判断数据已经得到,但是不用取出来,
而是将这个对象传递给别的数据处理程序进行操作的情况
reader还有一系列的get方法,getString getBoolean...
几个特殊的get方法
reader.getName(i) -- 获取列名
9. 可空类型
(数据库中的数据是可以为空的 如int类型的列是可以为空) 那么在使用reader时要注意空类型的处理
Nullable<int> num; //可空的整数类型
//可以模拟任何一种值类型,在使用上与正常的值类型完全一样
num = 10;
Nullable num有属性HasValue 如果为空 -- false 值 -- true
int n = num.HasValue? num.Value: 0;
简写形式 int n = num?? 0;
//第一种处理为空的方法 3代表第三列
DateTime dt1 = reader.IsDBNull(3)?DateTime.MinValue : reader.getDateTime(3);
判断是否是数据库中的空,如果是空,就代表是非正常时间;如果不为空,采用get系方法
//第二种处理为空的方法
Nullable<DateTime> dt2 = reader.IsDBNull(3)? null:(Nullable<DateTime>)reader.getDateTime(3);
DateTime? dt3 = reader.IsDBNull(3)? null:(DateTime?)reader.getDateTime(3);
字符串的空 和 数据库中的数据为空 是两个概念
字符串的空:IsNullOrEmpty
数据库中的空:DBNull
10. 如果一次想执行两个sql语句,可以使用reader.nextResult遍历所有结果
可以利用一个cmd对象进行sql语句的切换,如
SqlCommand cmd = new SqlCommand{
cmd.CommandText = sql; //sql语句
cmd.connection = conn; //连接对象
}
11. 案例:
1)从SQL Server中导出XML文件
2)将XML文件解析并导入SQL Server中
第一种方法
foreach (XElement e in xDoc.Root.Elements())
{
//每一个e就是一行数据
new SqlParameter("@name",e.Element("name").Value),
string.IsNullOrEmpty(e.Element("name").Value)? DBNull.Value:(object)e.Element("name").Value;
}
第二种方法
foreach (XElement e in xDoc.Descendants().Where(e=>e.Name == "stu"))
{}
12. DataSet类
数据库 DataSet
架构 命名空间
表 DataTable
列或者字段 DataColumn
行 DataRow
约束 属性
在.NET Framework3.5以后基本就不使用DataSet了--使用泛型
第一行(包含字段,字段有类型)就相当于一个类,每条记录就是对象,一张表就相当于一个集合
DataSet ds = new DataSet();
using(SqlDataAdapter sda = new SqlDataAdapter(sql,connStr))
{
sda.Fill(ds);
}
13. 数据库配置文件
应用程序配置文件App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="connStr01" connectionString="server=.;database=MyTestDB;uid=sa;pwd=123;"/>
<add name="connStr02" connectionString="server=.;database=MyTestDB;uid=sa;pwd=123;"/>
<add name="connStr03" connectionString="server=.;database=MyTestDB;uid=sa;pwd=123;"/>
</connectionStrings>
</configuration>
为了使用ConfigurationManager类,先要在引用中添加System.Configuration
//使用ConfigurationManager类获得在App.config文件中的连接字符串
string connStr = ConfigurationManager.ConnectionStrings[name].ConnectionString;