什么是Ado.Net
它是一种数据访问技术,应用程序可以连接到数据库,并以各种方式来操作其中的数据。一个COM组件库,.Net中数据优先选择的数据访问接口。
ADO:ActiveX Data Objects 早期开发人员用来访问数据的组件。.Net Ado.Net 逐步取代Ado。
他们之间的关系?
Ado.Net 是Ado的升级版,严格上,它们又是俩种截然不同的方式。
技术上:Ado oledb接口 ,基于COM技术,
Ado.Net 拥有自己的接口,基于.Net体系架构。
组成
- DataSet 非连接的核心组件。独立于任何数据源的数据访问,多种不同的数据源。
- Data Provider(数据提供程序):用于连接数据库、执行命令、检索结果
- SQLServer数据提供程序 System.Data.SqlClient命名空间
- OLEDB的数据提供程序 System.Data.Oledb命名空间
- ODBC的数据提供程序 System.Data.Odbc命名空间
- Oracle数据提供程序 System.Data.Oracle命名空间
- Connection 提供与数据源的连接 SqlConnection
- Command 执行数据库命令的对象 SqlCommand
- DataReader 从数据源中提供快速的,只读的数据流 SqlDataReader
- DataAdapter 提供DataSet对象与数据源的桥梁。Fill Update
SqlConnection介绍
Ado.Net访问数据库的步骤
- 连接到数据库
- 打开连接
- 创建执行命令对象
- 执行命令
- 关闭连接
SqlConnection类继承于DbConnection抽象基类,不能被实例化。提供与SQLServer数据库的连接
常用属性
- Database:要连接数据库名称
- DataSource:数据源 localhost:ip
- State:连接状态
- ConnectionTimeout:
- state
- Closed 已关闭
- Open 打开
- Connecting 正在连接
- Executing 正在执行命令
- Fetching 正在检索
- broken 连接中断
连接字符串
连接字符串是什么?
字符串,一组被格式化的键值对,数据源在哪里,数据库名,提供什么样访问信任级别,其他相关信息。
格式:一组元素组成,一个元素–键值对,各个元素之间用;隔开。
SQLServer连接字符串
SqlConnection conn = new SqlConnection();
conn.ConnectionString = "";
string connStr = "Data Source=localhost; Initial Catalog=TestNewBase;UserId=sc; Password=ysdsyyn";
Windows身份验证
SqlConnection conn = new SqlConnection();
conn.ConnectionString = "";
string connStr = "Data Source=localhost;Initial Catalog=TestBase;Integrated Security=SSPI";
MySQL
Data Source 数据源; Initial Catalog 数据库名;UserId账号;password密码。
Oracle
Data Source 数据源;UserId 账号;password密码。
Access
Provider=Microsoft.Jet.OLEDB.4.0; DataSource=文件的绝对路径;UserId=admin;Password=1234。
构建连接字符串(连接数据库)
专门的类来构建字符串 DbConnectionStringBuilder 基类 SqlConnectionStringBuilder 程序代码中写连接字符串。
配置文件中配置连接字符串
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<connectionStrings>
<add name="connStr" connectionString="server=localhost; database=TestNewBase;uid=sa; pwd=ysdysyn"
providerName="System.Data.SqlClient"/>
</connectionStrings>
<appSettings>
<add key="connStr" value="server=localhost; database=TestNewBase;uid=sa; pwd=ysdysyn"/>
</appSettings>
</configuration>
cs文件
SqlConnection conn = new SqlConnection();
string connStr = ConfigurationManager.ConnectionStrings["connStr"].ConnectionString;
string connStr = ConfigurationManager.AppSettings["connStr"].ToString();
conn.ConnectionString = connStr;
conn.Open();
conn.Close();
连接池
为什么我们要用连接池?
它非常耗时耗力一件事,有这几个阶段:建立物理通道,服务器初次握手,分析连接字符串,身份验证,运行检查。
可重复利用已连接的连接池
连接池是什么?
优化容器,存放了一定数量的鱼数据库服务器的物理连接。
需要容器里取出一条空闲的连接,而不是创建一条新的连接。
作用 :减少了连接数据库的开销,从而提高了应用程序的性能。
分类:类别区分,同一时刻同一应用程序域可以有多个不同类型的连接池。
什么来标识区分:进程、应用程序域、连接字符串 windows标识、共同组成的签名来标识区分;对同一领域来说,由连接字符串来区分,打开一条连接,如果这条连接的类型签名与现有的连接不匹配,就会创建一个新的连接池,反之则不会创建,他们会共用同一个连接池。
如何分配连接
根据连接请求的类型,找到与它相匹配的连接池,尽力的分配一条空闲的连接。
有空闲的连接,返回这条连接,用完的话,会创建一个新链接添加到连接池中;到达最大连接数时,等待,直至有空闲连接。
移除无效连接
不能真确的连接到数据库服务器的连接,连接池存储的与数据库服务器的链接数量是有限的。无效的连接,我们应当移除。浪费连接池空间,连接池管理器会处理吴小莲姐的移除问题。
回收连接
释放使用完的连接,应当及时关闭或释放,conn对象的CLose Dispose 连接回到连接池。
三个属性
- Max Pool Size : 最大连接数
- Min Pool Size:最小连接数
- Pooling 是否启用连接池 true
SqlCommand介绍及创建
对SQLServer数据库执行的一个T-SQL语句或存储过程
重要属性
- Connection:SQLCommand对象使用的SQLConnection
- CommandText:获取或设置要执行的T-SQL语句或存储过程名
- CommandType:CommandText.Text–执行的是一个sql语句;CommandText.StoredProcedure–执行的是一个存储过程
- Parameters:SqlCommand对象的命令参数集合 空集合
- Transaction:获取或者设置要在其中执行的事务。
创建 - 创建命令,执行命令的对象,执行命令
- 命令–T-SQL或存储过程==数据库里已创建好
- SQLCommand对SQLServer数据库执行的一个T-SQL语句或存储过程
- SQLCommand对象:Ado.Net中执行数据库命令的对象
- SQLCommand创建
- ExecuteNonQuery:返回增改删的行数
- ExecuteScalar方法:查询出的行数
- ExecuteReader:查询返回1一个对象:SqlDataReader数据流
- 如果执行不带参数的ExecuteReader,关闭dr,并不会关闭连接
- 如果执行带参数的ExecuteReader,关闭dr就会关闭连接,关闭连接也会关闭dr。
SQLParameter
定义:表示SQlCommand对象的参数,或于DataSet中列的映射
常用属性
- Dbtype参数的sqlDbType(数据类型,数据库的类型)
- Driection 参数的类型,输入,输出,输入输出,返回值参数
- ParameterName参数名称
- Size最大大小 字节为单位
- value 参数的值
- Sqlvalue 作为SQL类型的参数的值
参数作用:不带任何条件,不是通过参数传递,拼接SQL,具体的值;拼接SQL容易被注入,转义–防注入
command添加参数的几种方法
- cmd.Parameters.Add()
- cmd.Parameters.AddWithValue()
- cmd.Parameters.AddRange()、
参数使用
输入参数
参数化SQL语句或存储过程,默认使用的参数–输入参数
!以下三种:用在存储过程里
输出参数
output 程序中是可以接收到存储过程里需要返回的值,而不是return
Direction:Output
输入输出参数
output进行标识 它需要传入值,也输出住 而不用return
Driection:InputValue
返回值参数
他不会出现在存储过程中,只可以返回int类型 return返回的值
SqlDataReader介绍
定义:提供一种从SQLServer数据库中读取只进的行流的方式。
特点:快递、轻量级、只读的,遍历访问每一行数据的数据流,向一个方向,一行一行的,不能向后读取,不能修改数据。
缺点:不灵活,只适合数据小的情况,读取数据,一直占用连接。
读取方式:Read()方法返回False时,就表示不再有数据行。
注意:连接对象一直保持Open状态,如果关闭连接,是不能读取数据的。使用完成后,应该马上调用close()关闭,不然Reader对象会一直占用连接的
创建方式:是不能直接构造的,cmd.ExecutdReader()来创建。cmd.ExecuteReader(CommandBehaviour.CloseConnection)–好处,关闭reader对象时,就会自动关闭连接。
读取时尽量使用与数据库字段类型相匹配的方法来取得对应的值,会减少类型不一致而增加类型转换操作性能损耗。
没有读取到末尾就要关闭reader对象时,先调用cmd.Cancel(),然后在调用reader.Close()
cmd.ExecuteReader()获取存储过程的返回值或输出参数,先调用reader.Close(),然后才能获取参数的值。
常用属性
- Conection:获取与Reader对象相关的SqlConnection
- FiedCount:当前行中的列数
- HasRows:reader是否含一行或者多行
- IsClosed:reader对象是否已关闭 true false
- Item[int]:列序号,给定列序号的情况,获取指定列的值,dr[1] object
- Item[string]:列名,获取指定列的值
常用方法 - Close():关闭dr
- GetInt32(序列号):根据数据类型相匹配的方法
- GetFieldType(i):获取数据类型的Type
- GetName(序列号):获取指定列的列名
- GetOrdinal(列名):获取指定列名的序列号
- Read():使dr前进到下一条记录
- NextResult()使dr前进到下一个记录
DataTable详解
概念:DataSet:数据在内存中的缓存(数据库)Ado.Net核心组件。DataTable:内存中一个表(数据库中的一个表)。
应用:DataSet中的成员使用,他可独立创建与使用。结合DataAdapter使用。
架构:列和约束来表示。DataColumn列
成员:行,DataRow
构造:DataTable()DataTable(表名)
常用属性
- Columns:列集合
- Rows:行的集合
- Contraints:约束的集合
- DataSet:DataTable所属的DataSet
- PrimaryKey:主键(列的数组)
- TableName:指定表名
方法
- AcceptChanges():提交更改
- RejectChanges():回滚更改
- Clear():清空数据
- Copy():复制架构和数据
- Clone():只复制架构,不包含数据
- Load(IDataReader):通过提供的IDataReader,用某个数据源的值来填充DataTable
- Merge(DataTable):合并,指定的dt合并到当前的dt里
- NewRow():创建一个DataRow,与Dt具有相同的架构
- Reset():将dt重置到最初状态
- Select():获取dt所有的行的数组(条件,排序)
DataSet详解
概念:DataSet是数据在内存中的缓存–内存中的数据库,DataTable内存数据库中的一个表,Ado.Net的核心组件
成员:一组DataTable组成,DataRelation相互关联,一起实施了数据的完整性
应用:三种:结合DataAdapter使用
- DataAdapter将数据填充到DataSet中
- DataAdapter将DataSet中的更改提交到数据库
- XML文档或文本加载到DataSet中
作用:ds将数据加载到内存中来执行,提高了数据访问的速度,提高了硬盘数据的安全性,程序运行的速度和稳定性
特性:独立性,不依赖于任何数据库,离线和连接。数据视图,数组操作,灵活性。
创建:DataSet()DataSet(名称)
SQLDataAdapter介绍与创建
SqlDataAdapter是什么?
适配器(桥接器):DataSet数据之间用于检索和保存数据的桥梁。
SQLDataAdapter类 --填充DataSet以及更新数据源的一组数据库命令和一个数据库连接
SQLDataAdapter是DataSet和SQLServer之间的桥接器
它是如何提供桥接的?
Fill填充到DataSet里,updata更改提交到数据库 数据保持一致。
SQLconnection SqlCommand一起使用,提高访问速度。
4个主要属性
- SelectCommand 查询 SqlCommand
- InsertCommand 插入记录
- UpdateCommand 更新数据库的记录
- DeleteCommand 删除记录
SQLDataAdapter对数据的操作也是建立在SqlCommand基础之上的。
4种创建方式
string connStr = ConfigurationManager.ConnectionStrings["connStr"].ConnectionString;
string sql = "select * from ProductInfos";
SqlConnection conn = new SqlConnection(connStr);
//1,设置SelectCommand
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand=new SqlCommand(sql, conn);
//2,通过SqlCommand对象来实例化一个adapter
SqlCommand cmd= new SqlCommand(sql, conn);
SqlDataAdapter adapter1= new SqlDataAdapter(cmd);
//3,插叙语句和连接对象来实例化一个adapter
SqlDataAdapter adapter2 = new SqlDataAdapter(sql, conn);
//4,查询语句和连接字符串,构建一个adapter
SqlDataAdapter adapter3 = new SqlDataAdapter(sql, connStr);
Adapter与Reader比较
相同:执行查询,将数据读取出来,一个或多个
- SqlDataReader:提供一种从数据库中读取数据流的方式
- SqlDataAdapter:DataSet与数据库之间的桥接器 Fill Update
不同的:
性能对比 | SqlDataReader | SqlDataAdapter |
---|---|---|
速度 | 快 | 慢 |
数据量 | 小 | 大 |
占用内存 | 小 | 大 |
连接状态 | 一直占用 | 断开和连接 |
读取方式 | 从头读到尾一条一条读,读一条丢一条,即时存储,不灵活, | 一次性加载到内存中,任意读取,灵活 |
是否可读 | 只读,不能修改 | 可读可写 |
不要求随意读取,不修改,数据量小–SqlDataReader,速度快,占用内存小。
可以随意读取,可以修改,数据量大的情况下–SQLDataAdapter,灵活性大,占用空间大,不一直占用连接。
事务
Ado.Net调用数据库事务
事务执行过程:开启,提交,回滚。
插入,故障,并未数据库,维护数据的完整性
Ado.Net如何调用事务–实质:调用一个普通的存储过程–里面的逻辑是一段事务代码
批量导入–数据库事务,不可能传入几千个参数–不具有可行性。
数据访问通用类封装
为什么要封装通用类?
数据交互:增删改查–相同的事:连接
T-SQL命令,Command–执行命令,选择执行方式–得到相应的结果–关闭连接。
我们如果把所有的过程写在一起,整个代码会杂乱无章,不清晰。
改善:一些相同的逻辑–封装起来,通用
作用:代码重利用,提高效率,不在考虑交互过程,逻辑清晰。
DBHelper类的内容规划 :
- 连接钥匙–连接字符串–配置文件–创建连接–连接释放–using()
- SqlCommand三种执行方法:
- 增删改
- ExecuteNonQuery()执行T-SQL,返回受影响的行数
- ExecuteScalar()执行查询,返回结果集第一行第一列的值,忽略其他行或列,返回object类型
- ExecuteReader()-执行查询,生成-SQLdataReader
- SQLDataAdapter填充ds,dt
- SQLTransaction CommandInfo:T-SQL 参数数组 CommandType //sql
封装类
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
namespace AdoNetCourse
{
public class DBHelper
{
private static readonly string ConnStr = ConfigurationManager.ConnectionStrings["connStr"].ConnectionString;
SqlConnection connection = null;
/// <summary>
/// 执行T-SQL,返回受影响的行数 insert update delete
/// </summary>
/// <param name="sql"></param>
/// <param name="cmdType"></param>
/// <param name="paras"></param>
/// <returns></returns>
public static int ExecuteNonQuery(string sql, int cmdType, params SqlParameter[] paras)
{
int count = 0;
using (SqlConnection conn = new SqlConnection(ConnStr))
{
SqlCommand cmd = new SqlCommand(sql, conn);
if (cmdType == 2)
cmd.CommandType = CommandType.StoredProcedure;
if (paras.Length > 0 && paras != null)
cmd.Parameters.AddRange(paras);
conn.Open();
count = cmd.ExecuteNonQuery();
conn.Close();
}
return count;
}
/// <summary>
/// 执行查询,返回结果集第一行第一列的值,忽略其他行或列,返回object类型
/// </summary>
/// <param name="sql"></param>
/// <param name="cmdType"></param>
/// <param name="paras"></param>
/// <returns></returns>
public static object ExecuteScalar(string sql, int cmdType, params SqlParameter[] paras)
{
object o = null;
using (SqlConnection conn = new SqlConnection(ConnStr))
{
SqlCommand cmd = new SqlCommand(sql, conn);
if (cmdType == 2)
cmd.CommandType = CommandType.StoredProcedure;
if (paras.Length > 0 && paras != null)
cmd.Parameters.AddRange(paras);
conn.Open();
o = cmd.ExecuteScalar();
conn.Close();
}
return o;
}
/// <summary>
/// 执行查询,生成-SQLdataReader
/// </summary>
/// <param name="sql"></param>
/// <param name="cmdType"></param>
/// <param name="paras"></param>
/// <returns></returns>
public static object ExecuteReader(string sql, int cmdType, params SqlParameter[] paras)
{
SqlDataReader dr = null;
SqlConnection conn = new SqlConnection(ConnStr);
SqlCommand cmd = new SqlCommand(sql, conn);
if (cmdType == 2)
cmd.CommandType = CommandType.StoredProcedure;
if (paras.Length > 0 && paras != null)
cmd.Parameters.AddRange(paras);
try
{
conn.Open();
dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
catch (SqlException ex)
{
conn.Close();
throw new Exception("执行查询异常", ex);
}
return dr;
}
public static DataTable GetDataTable(string sql, int cmdType, params SqlParameter[] paras)
{
DataTable dt = null;
using (SqlConnection conn = new SqlConnection(ConnStr))
{
SqlCommand cmd = new SqlCommand(sql, conn);
if (cmdType == 2)
cmd.CommandType = CommandType.StoredProcedure;
if (paras.Length > 0 && paras != null)
cmd.Parameters.AddRange(paras);
SqlDataAdapter da = new SqlDataAdapter(cmd);
conn.Open();
da.Fill(dt);
conn.Close();
}
return dt;
}
public static bool ExecuteTrans(List<string> listSQL)
{
using(SqlConnection conn = new SqlConnection(ConnStr))
{
conn.Open();
SqlTransaction trans = conn.BeginTransaction();
SqlCommand cmd = conn.CreateCommand();
cmd.Transaction = trans;
try
{
for(int i = 0; i < listSQL.Count; i++)
{
cmd.CommandText = listSQL[i];
cmd.ExecuteNonQuery();
}
trans.Commit();
return true;
}
catch(SqlException ex)
{
trans.Rollback();
throw new Exception("执行事务出现异常",ex);
}
}
}
}
}