【重读MSDN之ADO.NET】ADO.NET连接

连接到ADO.NET中的数据源

在 ADO.NET 中,通过在连接字符串中提供必要的身份验证信息,使用 Connection 对象连接到特定的数据源。使用的 Connection 对象取决于数据源的类型。随 .NET Framework 提供的每个 .NET Framework 数据提供程序都具有一个 DbConnection 对象,适用于 SQL Server的.NET Framework 数据提供程序包括一个 SqlConnection 对象。

建立连接

要连接到 Microsoft SQL Server , 请使用 SQL Server .NET Framework 数据提供程序的 SqlConnection 对象。

关闭连接

在使用完连接时一定要关闭连接,以便连接可以返回池。如果在 C# 代码中存在 Using 块,将自动断开连接,即使发生无法处理的异常。也可以使用适合所使用的提供程序的连接对象的 Close 或 Dispose 方法。不是显式关闭的连接可能不会添加或返回到池中。例如,如果连接已超出范围但没有显式关闭,则仅当达到最大池大小 而该连接仍然有效时,该连接才会返回到连接池中。

注意

不要在类的Finalize方法中对 Connection、DataReader 或任何其他托管对象调用 Close 或 Dispose 。在终结器中,仅释放类直接拥有的非托管资源。如果类不拥有任何非托管资源,则不要在类定义中包含 Finalize 方法。

注意

从连接池中获取连接或将连接返回到连接池中时,服务器上不会引发登录和注销事件,这是因为在将连接返回到连接池时实际上并没有将其关闭。

连接到SQL Server

以下代码示例演示如何创建并打开与SQL Server数据库的连接。

using (var connection = new SqlConnection(ConnectionStr))
{
     connection.Open();
}

连接事件

使用 StateChange 事件

StateChange 事件在 Connection 的状态改变时发生。 StateChange 事件接收 StateChangeEventArgs,使能够使用 OriginalState 和 CurrentState 属性来确定 Connection 状态的改变。

以下代码示例在 Connection 的状态改变时使用 StateChange 事件将消息写入控制台。

connection.StateChange += connection_StateChange;

static void connection_StateChange(object sender, StateChangeEventArgs e)
{
   Console.WriteLine("The current Connection state has changed from {0} to {1}.", e.OriginalState, e.CurrentState);
}

在 ADO.NET 中的连接字符串

连接字符串包含作为参数从数据提供程序传递到数据源的初始化信息。其语法取决于数据提供程序,并且会在试图打开连接的过程中对连接字符串进行分析。语法错误会生成运行时异常,但其他错误只有在数据源收到信息后才会发生。经过验证后,数据源将应用连接字符串中指定的选项并打开连接。

连接字符串的格式是使用分号分隔的键/值参数对列表:

keyword1=value; keyword2=value;

关键字不区分大小写,并将忽略键/值对之间的空格。不过,根据数据源的不同,值可能是区分大小写的。任何包含分号、单引号或双引号的值必须用双引号引起来。

连接字符串生成器

连接字符串生成器旨在排除推测,防止出现语法错误和安全漏洞。

下面的示例演示SqlConnectionBuilder如何处理为Initial Catalog设置插入的额外值。

 var builder = new SqlConnectionStringBuilder();
 builder.DataSource = "(local)";
 builder.IntegratedSecurity = true;
 builder.InitialCatalog = "AdventureWorks;NewValue=Bad";

 Console.WriteLine(builder.ConnectionString);

输出结果表明,通过用双引号转义该额外值而不作为新的键/值对将其追加到连接字符串,SqlConnectionStringBuilder可以正确处理此额外值。

Data Source=(local);Initial Catalog="AdventureWorks;NewValue=Bad";Integrated Security=True

使用外部配置文件

外部配置文件是单独的文件,此类文件包含由一部分组成的配置文件的片段。外部配置文件由主配置文件引用。如果在部署完应用程序后连接字符串可能会被编辑,那么将connectionStrings节存储在物理上独立的文件中会很有用。

若要将连接字符串存储在外部配置文件中,请创建一个只包含connectionStrings节的单独的文件。不要包含任何其他的元素、节或属性。此示例演示外部配置文件的语法。

<connectionStrings>
  <add name="SQLServerConnectionString"
       connectionString="server=DTSZOPAULHUANG\SQLEXPRESS;initial catalog=TSQLFundamentals2008;integrated security=true"
       providerName="System.Data.SqlClient"/>
</connectionStrings>

在主应用程序配置文件中,可以使用configSource属性指定外部文件的完全限定名和位置,此示例引用名为connections.config的外部配置文件。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>

  <connectionStrings configSource="connections.config"></connectionStrings>
</configuration>

连接字符串语法

Windows身份验证

建议使用Windows身份验证(有时也称为"集成安全性")连接到支持其的数据源。连接字符串中使用的语法根据提供程序的不同而不同。下面演示 SQL Server .NET Framework 数据提供程序的 Windows 身份验证语法。

Integrated Security=true;
//or
Integrated Security=SSPI;

下列语法使用 Windows 身份验证连接到特定的数据库。

connectionString="server=DTSZOPAULHUANG\SQLEXPRESS;initial catalog=TSQLFundamentals2008;integrated security=true" 
SQL Server  登录

Windows 身份验证是用于连接到 SQL Server 的首选方法。但是,如果需要 SQL Server 身份验证,请使用下列语法来指定用户名和密码。

connectionString="server=DTSZOPAULHUANG\SQLEXPRESS;initial catalog=TSQLFundamentals2008;User ID=****;Password=****;Persist Security Info=False"

安全性注意

Persist Security Info 关键字的默认设置为 false .如果将其设置为 true ,则允许在打开连接后通过连接获取安全敏感信息(包括用户 ID 和密码)。保持将 Persist Securiy Info 设置为 false ,以确保不受信任的来源不能访问敏感的连接字符串信息。

注意

Windows 身份验证优先于 SQL Server 登录。如果同时指定 Integrated Securiy=true 以及用户名和密码,将忽略用户名和密码,而使用 Windows 身份验证。

SQL Sever 连接池

概述

连接到数据源可能需要很长时间。为了最大程度地降低打开连接的成本,ADO.NET 使用一种称为连接池的优化技术,这种技术可最大程度地降低重复打开和关闭连接所造成的成本。

连接到数据库服务器通常由几个需要很长时间的步骤组成。必须建立物理通道,必须与服务器进行初次握手,必须分析连接字符串信息,必须由服务器对连接进行身份验证等等。

实际上,大多数应用程序仅使用一个或几个不同的连接配置。这意味着在执行应用程序期间,许多相同的连接将反复地打开和关闭。为了使打开连接花费的系统开销最小,ADO.NET 使用称为连接池的优化方法。

连接池使新连接必须打开的次数得以减少。池进程保持物理连接的所有权。通过为每个给定的连接配置保留一组活动连接来管理连接。每当用户在连接上调用 Open 时,池进程就会查找池中可用的连接。如果某个池连接可用,会将该连接返回给调用者,而不是打开新连接。应用程序在该连接上调用 Close 时,池进程会将连接返回到活动连接池中,而不是关闭连接。连接返回到池中之后,即可在下一个 Open 调用中重复使用。

只有配置相同的连接可以建立池连接。ADO.NET 同时保留多个池,每种配置各一个。在使用集成的安全性时,连接按照连接字符串以及 Windows 标识分到多个池中。还根据连接是否已在事务中登记来建立池连接。池连接可以显著提高应用程序的性能和可缩放性。默认情况下,在 ADO.NET 中启用连接池,除非显式禁用。

为了比较形象的比较在打开及关闭连接池时的效果,下面进行示例演示。示例1是默认打开连接池进行多次数据库操作情况下的耗时情况,示例2是主动关闭连接池后对应的耗时情况。

示例1:

<connectionStrings>
  <add name="SQLServerConnectionString"
       connectionString="server=DTSZOPAULHUANG\SQLEXPRESS;initial catalog=TSQLFundamentals2008;Integrated Security=true;"
       providerName="System.Data.SqlClient"/>
</connectionStrings>
    public static class DataAccess
    {

        private static string _connectionString = null;

        public static int ExecuteNonQuerySql(string sql, SqlParameter[] sqlParameters = null)
        {
            _connectionString = ConfigurationManager.ConnectionStrings["SQLServerConnectionString"].ConnectionString;

            using (var connection = new SqlConnection(_connectionString))
            {
                //connection.StateChange += connection_StateChange;

                var commmand = connection.CreateCommand();

                commmand.CommandType = CommandType.Text;
                commmand.CommandText = sql;
                if (sqlParameters != null)
                {
                    commmand.Parameters.AddRange(sqlParameters);
                }

                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();

                connection.Open();

                Console.WriteLine(stopwatch.ElapsedMilliseconds);

                return commmand.ExecuteNonQuery();
            }
        }
    }
        private void btnUpdate_Click(object sender, EventArgs e)
        {
            string sql = "UPDATE Sales.Shippers SET CompanyName = @CompanyName, Phone = @Phone WHERE ShipperId = @ShipperId";

            var sqlParameters = new List<SqlParameter>();

            sqlParameters.Add(new SqlParameter("CompanyName", "SML"));
            sqlParameters.Add(new SqlParameter("Phone", "13266779613"));
            sqlParameters.Add(new SqlParameter("ShipperId", 1));

            int result = DataAccess.ExecuteNonQuerySql(sql, sqlParameters.ToArray());

            MessageBox.Show(result.ToString());
        }

//测试结果

示例2:修改连接字符串,使之禁用连接池,其他部分均不变动。

<connectionStrings>
  <add name="SQLServerConnectionString"
       connectionString="server=DTSZOPAULHUANG\SQLEXPRESS;initial catalog=TSQLFundamentals2008;Integrated Security=true;Pooling=False"
       providerName="System.Data.SqlClient"/>
</connectionStrings>

//测试结果

池的创建和分配

在初次打开连接时,将根据完全匹配算法创建连接池,该算法将池与连接中的连接字符串关联。按进程、应用程序域、连接字符串以及 Windows 标识(在使用集成的安全性时)来建立池连接。连接字符串还必须是完全匹配的;按不同顺序为同一连接提供的关键字将分到单独的池中。

在以下的示例中创建了三个新的 SqlConnection 对象,但是管理时只需要两个连接池。注意连接字符串的不同,可以通过查看 connection 对象的 ClientConnectionId 属性查看连接的 ID。

    public class Testing
    {
        public void Test()
        {
            using (SqlConnection connection = new SqlConnection(
                @"server=DTSZOPAULHUANG\SQLEXPRESS;initial catalog=TSQLFundamentals2008;Integrated Security=true;"))
            {
                connection.Open();
                // Pool A is created.
                Console.WriteLine(connection.ClientConnectionId);
            }

            using (SqlConnection connection = new SqlConnection(
               @"server=DTSZOPAULHUANG\SQLEXPRESS;initial catalog=TSQLFundamentals2008;Integrated Security=SSPI;"))
            {
                connection.Open();
                // Pool B is created because the connection strings differ.
                Console.WriteLine(connection.ClientConnectionId);
            }

            using (SqlConnection connection = new SqlConnection(
              @"server=DTSZOPAULHUANG\SQLEXPRESS;initial catalog=TSQLFundamentals2008;Integrated Security=true;"))
            {
                connection.Open();
                // The connection string matches pool A.
                Console.WriteLine(connection.ClientConnectionId);
            }
        }
    }

//测试结果

从结果可以清楚的看到第一和第三个连接对象使用的是同一个连接。第二个连接对象使用得是新的连接。

如果MinPoolSize在连接字符串中未指定或指定为零,池中的连接将在一段时间不活动后关闭。但是,如果指定的MinPoolSize 大于零,在AppDomain被卸载并且进程结束之前,连接池不会被破坏。非活动或空池的维护只需要最少的系统开销。

添加连接

当创建一个池后,将创建多个连接对象并将其添加到该池中,以满足最小池大小的要求。连接根据需要添加到池中,但是不能超过指定的最大池大小(默认值为100)。连接在关闭或断开时释放回池中。在请求 SqlConnection 对象时,如果存在可用的连接,将从池中获取该对象。连接要可用,必须未使用,具有匹配的事务上下文或未与任何事务上下文关联,并且具有与服务器的有效链接。

连接池进程通过在连接释放回池中时重新分配连接,来满足这些连接请求。如果已达到最大池大小且不存在可用的连接,则该请求将会排队。然后,池进程尝试重新建立任何连接,直至到达超时时间。如果池进程在连接超时之前无法满足请求,将引发异常。

池碎片

因为集成安全性产生的池碎片

连接根据连接字符串以及用户标识来建立池连接。因此,如果使用网站上的基本身份验证或 Windows 身份验证以及集成的安全登录,每个用户将获得一个池。尽管这样可以提高单个用户的后续数据库请求的性能,但是该用户无法利用其他用户建立的连接。这样还使每个用户至少产生一个与数据库服务器的连接。这对特定的 Web 应用程序结构会产生副作用。

因为许多数据库产生的池碎片

许多 Internet 服务提供商在一台服务器上托管多个网站。他们可能使用单个数据库确认窗体身份验证登录,然后为该用户或用户组打开与特定数据库的连接。与身份验证数据库的连接将建立连接池,供每个用户使用。但是,每个数据库的连接存在一个独立的池,这会增加与服务的连接数。

这也会对应用程序设计产生副作用。可通过一种相对简单的方法来避免此副作用,而不会影响连接到 SQL Server 时的安全性。连接到服务器上的相同数据库而不是为每个用户或组连接到单独的数据库,然后执行 T-SQL USE 语句来切换所需数据库。

时间: 2024-10-11 03:18:59

【重读MSDN之ADO.NET】ADO.NET连接的相关文章

ADO.NET基础巩固-----连接类和非连接类

      最近的一段时间自己的状态还是不错的,早上,跑步,上自习看书,下午宿舍里面编程实战,晚上要么练习代码,要么去打球(在不打就没机会了),生活还是挺丰富的. 关于C#的基础回顾就先到前面哪里,这些要自己在工作中慢慢的去体会,不是说看书就可以掌握的.我们都是从学生时代过来的知道每个人的学习情况是不一样的,所以找到自己的学习节奏是最好不过的. 下面是关于访问数据库[ADO.NET]的学习,之前刚开始学习的时候把这些基本的都过了一遍,但是长时间不使用,一些基本的用法还是会遗忘的.     一:关

ADO.NET之9-非连接模式,内存中的数据库DataSet,DataTable---ShinePans

DataSet被称作数据集,可以比作内存中的数据库,DataSet为ADO.NET核心,支持ADO.NET断开式,分布式数据方案的核心对象也是实现基于非连接的数据查询核心组件 DataTable常用属性: 属性 说明 Columns 获取属于该表的列的集合 Rows 获取属于该表的行的集合 TableName 获取或设置DataTable的名称 DataTable方法: 方法 说明 AcceptChanges 提交自上次调用AcceptChanges以来对该表进行的所有更改 Clear 清除Da

ADO和ADO.NET的区别

ADO.NET是ADO的后继版本,主要目的是在.NET Framework中更容易地创建分布式. 数据共享的应用程序,它提供了一个数据访问接口,以便和OLE DB数据源进行通信,如 SQL SERVER.应用程序可以使用ADO.NET连接这些数据源,并检索.处理和更新数据. 可以说ADO.NET是在ADO的基础上,又进一步的扩展,提供了更多新的工具,可以获取 一个真正断开连接的数据体系结构,可以将不同数据源中的数据组合起来,并优化了和 数据库交互的功能. 下面是ADO和ADO.NET之间一些数据

ADO.NET (二)—— ADO和ADO .NET对比

ADO.NET (二)-- ADO和ADO .NET对比 我们知道ADO.NET的两大核心组件分别是Data Provider和DataSet.如果说 DataSet是ADO.NET的心脏,那么Data Provider绝对是ADO.NET的左臂右膀. Data Provider提供了访问外部数据数据源的可能性,而且外部的数据源是多样的.本 文将详细说明.NET数据提供程序的作用以及如何访问不同的数据源. 详情细看<ADO.NET技术>             对ADO和ADO.NET的详细比

[转帖]ODBC、OLEDB、ADO、ADO.NET

一文详解ODBC.OLEDB.ADO.ADO.NET之间的关系 2019年01月16日 21:28:38 LoveMIss-Y 阅读数:66更多 所属专栏: 白话C#高级编程 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/qq_27825451/article/details/86515141 相信看到这篇文章的人,心中肯定有这样的想法:ODBC.OLEDB.ADO.ADO.NET貌似都是访问数据库的东东,那么他们之间有什么区别,又有什么联系呢

ADO与ADO.Net

在介绍ADO.Net之前先让我们回顾一下在红皮书中学习的ADO的内容. ADO(ActiveX Data Objects),我们称它为一种用于数据访问的对象模型,<VB.Net>视频中称它为用于存取资料库的物件集合.资料库就是数据,物件即对象.这样看来两种说法完全一样.提起ADO,我们只要问自己两个问题: 它是什么?  --对象的集合 干什么用的?--访问数据 这样我们对ADO就了解个八九不离十. 我们再来看看ADO所处的地位: ADO.Net同之前我们学的ADO一样,它和ADO有着相同的本质

ADO.NET 之断开连接层

定义: 使用ADO.NET断开连接层,就会使用System.Data命名空间的许多成员(主要是DataTable.DataTable.DataRow.DataColumn.DataView和DataRelation)在调用层建模内存中的数据库数据. 当使用ADO.NET断开式访问方式的时候,不需要连接到数据库,但任然会使用拦截和命令对象.我们还会补充一个叫做数据适配器的特殊对象(扩展自DbDataAdapter抽象类)来获取和更新数据. DataSet的作用 DataSet类型内部包含了3个强类

ADO.NET笔记——使用连接池

相关知识: 连接池的意义: 应用程序往往涉及大量的,并发的数据访问操作 数据库服务器能够同时维系的连接数量非常有限.如果某个数据库访问操作不及时关闭连接,就会减少其他调用对数据库访问的机会.因此,一般需要尽可能晚的打开连接,尽可能早的关闭连接 反复的创建和销毁连接对象,或者反复的打开和关闭实际的连接(从应用程序到数据库服务器,可能跨网络),其开销是比较大的,也是不划算的 采用连接池,在池中缓存若干个链接对象.如果有调用需要使用连接,则从池中取出一个:调用完成后,并不销毁连接,而是将连接放回池中,

基于ADO的远程Oracle连接

最近在一个通过MFC做一个界面,通过这个界面可以对布置在另一台服务器上的数据库MySQL.SQl Server.Oracle进行增删创建表的操作.其中我通过ADO很快就完成了对MySQL和SQL Server的控制.但是Oracle的连接就麻烦很多,我完成这个项目的大部分的时间都在研究怎么与Oracle数据库互通. 先声明下我的电脑环境,没有装ORACLE客户端,WIN7_64位操作系统,使用的编译器是VC6.服务器用的是WIN10的系统,Oracle的版本为11.2.0.1.0,我客户端安装了