ADO.NET笔记三

    技术2026-01-12  39

    事 务

     

    ACID

      Atomic :要么全成功,要么全失败   Consistent : Isolated :每个事务都是一个独立主体,不会影响其它事务。   Durable :

    ASP.NET web application 中三种基本事务类型:

    1.         Stored procedure transactions: 整个事务完全在数据库内部发生,所以性能最好。缺点:必须用 sql 语句编写事务逻辑。

    2.         Client-initiated (ADO.NET) transactions: 这些事务被我们编写的程序控制。但在底层会执行与 Stored procedure transactions 一样的命令。在我们编写的程序中用某些 ADO.NET 对象将这些底层细节给包住了,对于我们来说是透明的。

    3.         COM+ transactions:

     

    事务会对系统的性能有所开销,其实用原则如下:

    1.         尽可能短的使用事务。

    2.         避免将 select 查询语句放到事务中,最好放到事务之前,这样会减少事务锁定的数据。

    3.         如果检索数据,尽可能压缩到必须的数据,减少锁定数据的数量。

    4.         最好在 stored procedures 中写入事务,而不是在 ADO.NET transactions ,这样效率更高,数据库服务器不必与系统有额外的数据交换。

    5.         如果有多项独立工作块,尽量将工作块用各自的事务,而不是放到一个大事务中。

    6.         Avoid updates that affect a large range of records if at all possible.

    7.         如果只是一个 UPDATE 或 DELETE 或 INSERT 语句,不需要声明事务,因为这些单一语句在数据库内部天生就是事务处理的。

     

    Client-Initiated ADO.NET Transactions

     

    例子:

    SqlTransaction tran = null;

    try

    {

    con.Open();// 打开连接

    tran = con.BeginTransaction();// 创建事务

    // Enlist two commands in the transaction.

    cmd1.Transaction = tran;// 将连个命令对象添加到事务中。

    cmd2.Transaction = tran;

    // Execute both commands.

    cmd1.ExecuteNonQuery();

    cmd2.ExecuteNonQuery();

    // Commit the transaction.

    tran.Commit();// 提交事务

    }

    catch

    {

    // In the case of error, roll back the transaction.

    tran.Rollback();// 如果有异常,事务回滚。

    }

    finally

    {

    con.Close();

    }

     

     

    Isolation Levels

    基本概念:

    Dirty reads (脏读):一个事务从数据库中读某值,而这值正是另一事务刚修改但还没提交。有回滚的可能。 Nonrepeatable reads (非重复读) : 在同一个事务中多次查询相同的行,可能返回不同的值。   Phantom rows ( 幻像读 ) : 在同一个事务中,当初始读时,无此数据,当再次读时,发现多了数据。

     

    不同的 Isolation Level 对应不同的锁

    锁的分类:

    l  Shared locks : 多用户可以利用同一个 Shared locks 来同步 读数据,但锁定的数据不可修改。

    l  Exclusive locks : 此锁可阻止两个以上 的事务同步 修改锁定的数据。当应用此锁时,其它用户无法读和修改数据。解决方法:在整个事务中,数据库锁住读的行。

     

    在 ADO.NET 中,我们可以自定义我们事务的 Isolation Level ,方法 : 将 IsolationLevel enumeration 值传到 Connection.BeginTransaction() 方法中。

     

    Values of the IsolationLevel Enumeration

    1.         ReadUncommitted : 无锁,级别最低,可能脏读,性能最好。

    2.         ReadCommitted ( SQL Server 默认): 用 Shared locks ,无脏读(即, 不能读取事务已修改,但未提交的记录 ),缺点: 不可重读( Non-Repeatable read )和幻读( phantom read )。

    3.         Snapshot :

    4.         RepeatableRead : 用 Shared locks ,避免了脏读和 不可重读( Non-Repeatable read ),无法避免幻读( phantom read )。

    5.         Serializable : range lock 。避免 幻读( phantom read ),但其效率低,用的少。

     

     

    Creating the Factory

     

    每种 provider 都提供自己的 Factory :

    1.         Sql Server : System.Data.SqlClient.SqlClientFactory

    2.         Oracle    : System.Data.OracleClient.OracleClientFactory

     

    System.Data.Common.DbProviderFactories 的静态方法 GetFactory() 根据 provider 名返回其 factory 对象。

    如:获得 SqlClientFactory :

    string factory = "System.Data.SqlClient";// 此字符串可放在系统配置文件里,

    DbProviderFactory provider = DbProviderFactories.GetFactory(factory);

     

    可用此 factory 创建 Connection 和 Command 对象。

     

    例子:

    <configuration>

    <connectionStrings>

    <add name="Northwind" connectionString=

    "Data Source=localhost; Initial Catalog=Northwind; Integrated Security=SSPI"/>

    </connectionStrings>

    <appSettings>

    <add key="factory" value="System.Data.SqlClient" />

    <add key="employeeQuery" value="SELECT * FROM Employees" />

    </appSettings>

    ...

    </configuration>

    Next, here ’ s the factory-based code:

    // Get the factory.

    string factory = WebConfigurationManager.AppSettings["factory"];

    DbProviderFactory provider = DbProviderFactories.GetFactory(factory);

    // Use this factory to create a connection.

    DbConnection con = provider.CreateConnection();

    con.ConnectionString =

    WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;

    // Create the command.

    DbCommand cmd = provider.CreateCommand();

    cmd.CommandText = WebConfigurationManager.AppSettings["employeeQuery"];

    cmd.Connection = con;

    // Open the Connection and get the DataReader.

    con.Open();

    DbDataReader reader = cmd.ExecuteReader();

    最新回复(0)