[ASP.NET学习笔记之六]开发高性能的ADO.NET应用

来源:互联网 发布:mysql更新语句怎么写 编辑:程序博客网 时间:2024/04/30 12:02

开发高性能的ADO.NET应用

ADO.NET概述

 

面向连接模型

l         ADO.net 1.x读取数据时必须保存稳定的连接而且在每个连接上只能使用一个DataReader

l         ADO.net 2.0无此限制!一个连接可以打开多个DataReader

 

ADO.NET性能最佳实践

选用合适的Data Provider

l         SQL Server .NET Data Provider

SQL Server 7.0 2000

通过TDS访问数据库

l         OLE DB .NET Data Provider

SQL Server 6.5, Microsoft Access, Oracle, 或其他具有

OLE DB 提供者的数据库。

l         ODBC .NET Data Provider

某些旧的系统

l         .NET Data Provider for Oracle

Oracle 8.1.7 或更高版本

l         Custom .NET Data Provider

[注意] 可以自定义Data Provider,这个接口在.NET是公开的,你能够自己实现这些类。

 

下面的图示数据库连接的比较:

Provider Factories

l         在应用开发时,我们很多时候并不清楚目标环境是什么数据库,特别是做产品的时候。

l         ADO.NET 1.x使用接口IConnection IDataAdapter等等)来实现在数据库的无关性,但程序员还是要写很多代码。

l         ADO.NET 2.0使用了一些数据库无关的抽象类接口,并提供“DbProviderFactory 来获得相应数据提供者。

真正的DataProvider。这是一个实现层,完成了数据库具体提供者。

DbProviderFactory Methods

CreateConnection

CreateCommand

CreateCommandBuilder

CreateConnection

CreateConnectionStringBuilder

CreateDataAdapter

CreateDataSourceEnumerator

CreateParameter

CreatePermission

 

相关资料可以查阅MSDN。我们可以通过它们创建访问数据库需要的连接指令 Adapter 参数 权限 数据源等等

DbProviderFactories methods

DbProviderFactories Method

Purpose

GetFactoryClasses()

Returns a DataTable of provider information from the information in machine.config

GetFactory(DataRow)

Returns the correct DbProviderFactory instance given a DataRow from the DataTable produced by GetFactoryClasses

GetFactory(string)

Returns the correct DbProviderFactory instance given a provider-invariant name string that identifies the provider

 

GetFactory(string):这里面string 你把可以把它写到配置文件(machine.config)

 

注册数据提供者

ADO.NET 2.0 可以在machine.config来注册数据提供者,在程序中可以按名字找到相应

数据提供者。通过下面的注册,当我要用SqlClient Data Provider就只知道是用这个类来实现的

<system.data>

  <DbProviderFactories>

    <add name="SqlClient Data Provider" invariant="System.Data.SqlClient" support="FF" description=".Net Framework Data Provider for SqlServer"

       type="System.Data.SqlClient.SqlClientFactory, System.Data,Version=2.0.3600.0, Culture=neutral,PublicKeyToken=b77a5c561934e089" />

    <!-- other provider entries elided -->

  </DbProviderFactories>

</system.data>

 

Factory例子(base

enum provider {sqlserver, oracle, oledb, odbc};

public DbConnection GetConnectionBaseClass()

{

    // determine provider from configuration

    provider prov = GetProviderFromConfigFile();

    DbConnection conn = null;

    switch (prov)

    {

        case provider.sqlserver:

            conn = new SqlConnection();

            break;

        case provider.oracle:

            conn = new OracleConnection();

            break;

        // add new providers as the application supports them

    }

    return conn;

}

为什么能够这样实现呢?这是因为ADO.NET2.0中的DBConenection抽象类,而在ADO.NET1.1中只有IConnenction这个接口

Factory例子(Adv

// get ProviderInvariantString from configuration

string provstring = GetProviderInvariantString();

DbProviderFactory fact = DbProviderFactories.GetFactory(provstring);

IDbConnection = fact.CreateConnection();

 

以上两种方式都能够实现DataProvider

 

数据库连接

连接

l         在方法中打开和关闭连接明确地关闭连接。

l         当使用DataReaders, 指定CommandBehavior.CloseConnection

l         当使用FillUpdate方法时,不要手工打开连接。

l         避免检查OleDbConnection State属性,带来额外的消耗。

l         使用连接池

连接池

在默认情况下,连接池自动打开。可以通过连接字符串的参数控制连接池:

Max Pool Size (default = 100)

Min Pool Size (default = 0)

Pooling (default = true)

       Conn.ConnectionString="Server=localhost; Integrated Security=SSPI; Database=Northwind;Max Pool Size=75; Min Pool Size=5;Pooling=true;";

 

打开和关闭连接

l         DataAdapter能根据需要自动打开和关闭连接。

l         使用Command对象时,则需要手动打开和关闭连接

 

SQL指令

l         校验SQL的输入并使用参数

l         仅返回需要的行和例

l         对大的数据集使用分页功能

l         批次执行SQL ,减少往返

l         如果没有数据返回则使用ExecuteNonQuery方法

l         当返回一个标量时,使用ExecuteScalar方法

l         不要在运行时间使用CommandBuilder

 

批次执行SQL

SqlCommand cmd = new SqlCommand();

cmd.CommandText = "ReadCustomerAndOrders";

// The stored procedure returns multiple result sets.

SqlDataReader myReader = cmd.ExecuteReader();

if (myReader.read())

    //... read first result set

    reader.NextResult();

if (myReader.read())

//... read

 

存储过程

l         尽量使用存储过程

       一般SQL语句需要执行五步:解释 解析 优化 编译 执行,所以存储过程只需要执行最后一步

l         对于OleDbCommand,指令类型为CommandType.Text

l         使用SqlCommand时,指令类型为CommandType.StoredProcedure

l         考虑使用Command.Prepare(),这是因为在后台做一个编译存储起来

l         尽可能使用输出参数

l         考虑在SQL ServerSET NOCOUNT ON。我们可以从查询分析器中可以看见没做一次执行,都会给一个统计反映多少行修改,我们可以把它关闭,使SQL语句执行更快。

参数

l         在存储过程上使用参数

SqlDataAdapter myCommand = new SqlDataAdapter("AuthorLogin", conn);

myCommand.SelectCommand.CommandTyp

e = CommandType.StoredProcedure;

SqlParameter parm=myCommand.SelectCommand.Parameters.Add("@au_id", SqlDbType.VarChar, 11);

parm.Value = Login.Text;

l         使用参数化SQL语句

SqlDataAdapter myCommand = new SqlDataAdapter SqlDataAdapter("SELECT au_lname, au_fname FROM Authors WHERE au_id = @au_id", conn);

SqlParameter parm = myCommand.SelectCommand.Parameters.Add("@au_id",SqlDbType.VarChar, 11);

parm.Value = Login.Text;

l         创建参数并指定类型

l         可将参数对象进行缓存

 

事务

l         使用数据库事务(存储过程)

BEGIN TRAN

UPDATE Orders SET Freight=@Freight Where OrderID=@OrderID

UPDATE [Order Details] SET Quantity=@Quantity Where OrderID=@OrderID

IF (@@ERROR > 0)

ROLLBACK TRANSACTION

ELSE

COMMIT TRANSACTION

[注意] 如果你的事务判断条件都在数据库里面,就考虑使用数据库事务,它的效率最高

l         使用ADO.NET的事务(编程)

SqlConnection conn = new SqlConnection(connString);

SqlTransaction trans = conn.BeginTransaction();

try

{

    SqlCommand cmd = new SqlCommand("MyWriteProc",conn, trans);

    cmd.CommandType = CommandType.StoredProcedure;

    cmd.Parameters.Add(.......);

    // additional transactioned writes to database

    trans.Commit();

}

catch

{

    trans.Rollback();

}

l         使用分布式事务,由多个数据库的更新,考虑分布式事务,虽然效率很差。

l         尽可能使用短事务,这是因为资源锁定的时间比较长。

l         使用适当的事务隔离级别,避免并发行很差。

l         避免死锁

 
原创粉丝点击