1.1 ADO.NET支持哪几种数据源?

  ① System.Data.SqlClient

  .NET程序员最常用的了。通过OLEDB或者ODBC都可以访问,但是SqlClient下的组件直接针对MSSQL,因此ADO.NET是为其专门做了一些优化工作。

  ② System.Data.OracleClient

  针对Oracle数据库产品且得搭配Oracle数据库的客户端组件(Oracle.DataAccess.dll)一起使用。

  ③ System.Data.OleDb

  该命名空间下的组件主要针对OLEDB(Microsoft提供的通向不同数据源的低级API)的标准接口,它还可以连接其他非SQL数据类型的数据源。OLEDB是一种标准的接口,实现了不同数据源统一接口的功能。

  ④ System.Data.Odbc

  该命名空间下的组件针对ODBC标准接口。

总体来说,ADO.NET为我们屏蔽了所有的数据库访问层次,提供了统一的API给我们,使我们无需考虑底层的数据源是具体的DataBase还是另一种标准接口。

下图直观地展示了ADO.NET与可能的数据源的连接:

二、ADO.NET和数据库的连接

2.1 简述数据库连接池

  数据库连接一般都被认为是一个性能成本相对较大的动作。

  (1)数据库连接池的基本概念

  一个存储数据库连接的缓冲池,由于连接和断开一个数据库的开销很大(经典的TCP三次握手和四次挥手),反复连接和断开数据库对于系统的性能影响将会非常严重。

  当一个用户新申请了一个数据库连接时,当数据库池内连接匹配的情况下,用户会从连接池中直接获得一个被保持的连接。在用户使用完调用Close关闭连接时,连接池会将该连接返回到活动连接池中,而不是真正关闭连接。连接回到了活动链接池中后,即可在下一个Open调用中重复使用。

默认情况下,数据库连接时处于启用状态的。我们也可以通过数据库连接字符串设置关闭数据库连接池.

(2)数据库连接的复用

   由于数据源和连接参数选择的不同,每个数据库的连接并不是完全通用的。因此,ADO.NET选择通过连接字符串来区分。一旦用户使用某个连接字符串来申请数据库连接,ADO.NET将判断连接池中是否存在拥有相同连接字符串的连接,如果有则直接分配,没有则新建连接。

(3)不同数据源的连接池机制

  ADO.NET组件并不直接包含连接池,而针对不同类别的数据源指定不同的连接池方案。对于SqlClient、OracleClient命名空间下的组件,使用的连接池是由托管代码直接编写的,可理解为连接池直接在.NET框架中运行。而对于OLEDB和ODBC的数据源来说,连接池的实现完全依靠OLEDB和ODBC提供商实现,ADO.NET只与其约定相应规范。

2.2 如何提高连接池内连接的重用率

  (1)连接池重用率低下的原因

  由于数据库连接池仅按照数据库连接字符串来判断连接是否可重用,所以连接字符串内的任何改动都会导致连接失效。数据库连接字符串中最常被修改的两个属性就是数据库名和用户名/密码。因此,对于多数据库的系统来说,只有同一数据库的连接才会被共用.

(2)如何提高数据库连接池重用率

这里提供一种能够有效提高数据库连接池重用率的方式,但是也会带来一点小安全隐患,在进行设计时需要权衡利弊关系,并根据实际情况来指定措施。

  ① 建立跳板数据库

  在数据库内建立一个所有权限用户都能访问的跳板数据库,在进行数据库连接时先连接到该数据库,然后再使用 use databasename 这样的SQL语句来选择需要访问的数据库,这样就能够避免因为访问的数据库不一致而导致连接字符串不一致的情况。

  下面的示例代码演示了这一做法:

// 假设这里使用Entry数据作为跳板数据库,然后再使用databaseName指定的数据库
using (SqlConnection connection = new SqlConnection("Server=192.168.80.100;Uid=public;Pwd=public;Database=Entry"))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
command.CommandText = string.Format("USE {0}", databaseName);
command.ExecuteNonQuery();
}

② 不使用数据库用户系统来管理系统权限

  这样做的结果就是永远使用管理员的账号来连接数据库,而在做具体工作时再根据用户的实际权限,使用代码来限定操作。

三、使用ADO.NET读写数据库

3.1 ADO.NET支持访问数据库的方式有哪些?

  一种是连接式的访问模式,而另外一种则是离线式的访问模式。

  (1)连接式的访问

  连接式的访问是指读取数据时保持和数据库的连接且在使用时独占整个连接,逐步读取数据。这种模式比较适合从数据量庞大的数据库中查询数据且不能确定读取数量的情况。使用XXXCommand和XXXDataReader对象来读取数据就是一个典型的连接式数据访问,这种模式的缺点就是:数据库连接被长时间地保持在打开的状态。

(2)脱机式的访问

  脱机式的访问并不是指不连接数据库,而是指一般在读取实际数据时连接就已经断开了。脱机式访问方式在连接至数据库后,会根据SQL命令批量读入所有记录,这样就能直接断开数据库连接以供其他线程使用,读入的记录将暂时存放在内存之中。脱机式访问的优点就在于不会长期占用数据库连接资源,而这样做的代价就是将消耗内存来存储数据,在大数据量查询的情况下该方式并不适用。例如,使用XXXDataAdapter和DataSet对象就是最常用的脱机式访问方式。

3.2 简述SqlDataAdapter的基本工作机制

  一个SqlDataAdapter对象,在数据库操作中充当了中间适配的角色,组织起数据缓存对数据库的所有操作,进行统一执行。一个SqlDataAdapter对象内实际包含四个负责具体操作的SqlCommand对象,它们分别负责查询、更新、插入和删除操作。

  如上图所示,实际上进行数据操作的是包含在SqlDataAdapter内的四个SqlCommand对象,而当SqlDataAdapter的Update方法被调用时,它会根据DataSet独享的更新情况而调用插入、删除和更新等命令。

3.3 如何实现批量更新的功能?

  (1)批量更新的概念

  使用XXXDataAdapter更新数据,由于每一行都需要都需要一个从程序集到数据库的往返,在大批量更新的情况下,效率是非常低的。可以考虑使用一次发送多条更新命令的处理方式,这就需要用到UpdateBatchSize属性。在.NET 2.0之后,SqlClient和OracleClient都支持这个属性,这里以SQL Server数据源为例,介绍一下UpdateBatchSize的基本使用。

UpdateBatchSize的值一共有三种:

  ① =0,DbDataAdapter将使用服务器能处理的最大批处理大小;

  ② =1,禁用批量更新;

  ③ >1,使用UpdateBatchSize操作批处理一次性发送的量;

当批量更新被允许时,SqlDataAdapter的Update方法将每次发送多条更新命令到数据库,从而提高性能。

  使用批量更新并不意味着SQL的合并或优化。批量的意义在于把多个发往数据库服务器的SQL语句放在一个请求中发送。例如,将UpdateBatchSize设置为20时,原本每个更新行发送一次更新命令将变为每20个更新行发送一次更新命令,而每个命令中包含了20个更新一行的命令。

public class DataHelper
{
private static readonly string conn_string = "Server=localhost;Integrated Security=true;database=TestDB";
//选择、更新、删除和插入的SQL命令
static readonly string SQL_SELECT = "SELECT * FROM DeptMaterialDetails";
static readonly string SQL_UPDATE = "UPDATE DeptMaterialDetails SET Department=@Department,Item=@Item,Number=@Number where Id=@Id";
static readonly string SQL_DELETE = "DELETE FROM DeptMaterialDetails where Id=@Id";
static readonly string SQL_INSERT = "Insert INTO DeptMaterialDetails (Department,Item,Number) VALUES (@Department,@Item,@Number)"; /// <summary>
/// 得到SqlDataAdapter,私有方法
/// </summary>
/// <param name="con"></param>
/// <returns></returns>
private static SqlDataAdapter GetDataAdapter(SqlConnection con)
{
SqlDataAdapter sda = new SqlDataAdapter();
sda.SelectCommand = new SqlCommand(SQL_SELECT, con);
sda.UpdateCommand = new SqlCommand(SQL_UPDATE, con);
sda.DeleteCommand = new SqlCommand(SQL_DELETE, con);
sda.InsertCommand = new SqlCommand(SQL_INSERT, con);
sda.UpdateCommand.Parameters.AddRange(GetUpdatePars());
sda.InsertCommand.Parameters.AddRange(GetInsertPars());
sda.DeleteCommand.Parameters.AddRange(GetDeletePars());
return sda;
} // 三个SqlCommand的参数
private static SqlParameter[] GetInsertPars()
{
SqlParameter[] pars = new SqlParameter[3];
pars[0] = new SqlParameter("@Department", SqlDbType.VarChar, 50, "Department");
pars[1] = new SqlParameter("@Item", SqlDbType.VarChar, 50, "Item");
pars[2] = new SqlParameter("@Number", SqlDbType.Int, 4, "Number");
return pars;
} private static SqlParameter[] GetUpdatePars()
{
SqlParameter[] pars = new SqlParameter[4];
pars[0] = new SqlParameter("@Id", SqlDbType.VarChar, 50, "Id");
pars[1] = new SqlParameter("@Department", SqlDbType.VarChar, 50, "Department");
pars[2] = new SqlParameter("@Item", SqlDbType.VarChar, 50, "Item");
pars[3] = new SqlParameter("@Number", SqlDbType.Int, 4, "Number");
return pars;
} private static SqlParameter[] GetDeletePars()
{
SqlParameter[] pars = new SqlParameter[1];
pars[0] = new SqlParameter("@Id", SqlDbType.VarChar, 50, "Id");
return pars;
} /// <summary>
/// 更新数据库,使用批量更新
/// </summary>
/// <param name="ds">数据集</param>
public static void Update(DataSet ds)
{
using (SqlConnection connection = new SqlConnection(conn_string))
{
connection.Open();
using (SqlDataAdapter adapater = GetDataAdapter(connection))
{
// 设置批量更新
adapater.UpdateBatchSize = 0;
adapater.Update(ds);
}
}
}
}

  

.NET基础拾遗(8)ADO.NET与数据库开发基础的更多相关文章

  1. .NET基础拾遗(6)ADO.NET与数据库开发基础

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开发基 ...

  2. AndoridSQLite数据库开发基础教程(10)

    AndoridSQLite数据库开发基础教程(10) 添加触发器 触发器(TRIGGER)是由事件来触发某个操作.这些事件包括INSERT.DELETE.UPDATE和UPDATE OF.当数据库系统 ...

  3. AndoridSQLite数据库开发基础教程(9)

    AndoridSQLite数据库开发基础教程(9) 添加视图 视图是从一个或几个基本表(或视图)中导出的虚拟的表.通过视图可以看到表的内容.下面为数据库添加视图,操作步骤如下: (1)打开的数据库,单 ...

  4. AndoridSQLite数据库开发基础教程(8)

    AndoridSQLite数据库开发基础教程(8) 添加索引 索引是一种通过预先排序和对表的一个或多个列构建索引表来优化数据库查找的手段.下面为表添加索引,操作步骤如下: (1)在打开的数据库中,单击 ...

  5. AndoridSQLite数据库开发基础教程(7)

    AndoridSQLite数据库开发基础教程(7) 为空表添加数据 开发者可以单击Data按钮,看到Students表中是没有数据的,创建好的Students表是一个空表.如图1.15所示.如果开发者 ...

  6. AndoridSQLite数据库开发基础教程(6)

    AndoridSQLite数据库开发基础教程(6) 为数据库添加添加空表 如果开发者想要往数据库中添加表和列,操作步骤如下: (1)在打开的数据库中,单击左下方的“+”按钮,弹出Table Edito ...

  7. AndoridSQLite数据库开发基础教程(5)

    AndoridSQLite数据库开发基础教程(5) 创建SQLite数据库 使用SQLiteManager创建数据库的操作步骤如下: (1)双击SQLiteManager工具,弹出SQliteMana ...

  8. AndoridSQLite数据库开发基础教程(4)

    AndoridSQLite数据库开发基础教程(4) 安装SQLiteManager 以下是SQLiteManager的安装步骤: (1)双击下载的.exe文件,弹出SQLiteManager Setu ...

  9. Andorid SQLite数据库开发基础教程(3)

    Andorid SQLite数据库开发基础教程(3) 数据库生成方式 数据库的生成有两种方式,一种是使用数据库管理工具生成的数据库,我们将此类数据库称为预设数据库,另一种是使用代码生成的数据库. 使用 ...

随机推荐

  1. uva 482 - Permutation Arrays

    <int, double> --> <int, string> 从而避免了输出格式: #include <vector> #include <strin ...

  2. rtmpdump代码分析 转

    RTMPdump 源代码分析 1: main()函数 rtmpdump 是一个用来处理 RTMP 流媒体的工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, ...

  3. vm安装不上vmtools

    vm的一些仿真机的配置项 isolation.tools.getPtrLocation.disable = “TRUE”isolation.tools.setPtrLocation.disable = ...

  4. 关于iOS上的对象映射公用方法-备

    具体的使用方法,请见下面说明,或者见工程里的单元测试代码.或者,参考原始文档: https://github.com/mystcolor/JTObjectMapping 使用方法 ======== 绝 ...

  5. Selenium IDE测试

    判断WEB程序是否能打开页面,并且打开了正确的页面,可以通过 assertTitle和assertLocation进行判断 并且这些操作不需要提供value. target就是期望的URL和页面标题, ...

  6. ural 1348 Goat in the Garden 2

    http://acm.timus.ru/problem.aspx?space=1&num=1348 #include <cstdio> #include <cstring&g ...

  7. 最全的TV视频应用合集,包含50多款客户端,有丰富直播点播

    这是我目前找到的 最好的视频应用合集,与坛友分享下.有50多款视频客户端,基本覆盖目前市面上口碑比较好的视频应用了. 里面有丰富的直播客户端,像 龙龙直播.泰捷直播.果子 Tv.More Tv等,还有 ...

  8. python 发邮件

    http://www.cnblogs.com/xiaowuyi/archive/2012/03/17/2404015.html http://my.oschina.net/lenglingx/blog ...

  9. Tradesy | IT桔子

    Tradesy | IT桔子 Tradesy www.tradesy.com   认领 关注 分享

  10. jQuery简单的Ajax调用示例

    jQuery确实方便,下面做个简单的Ajax调用: 建立一个简单的html文件: <!DOCTYPE HTML> <html> <head> <script ...