技术开发 频道

理解.NET 2.0中的事务


3. .NET 2.0中的事务


    通过登记正在执行的事务性工作类型的资源管理器,.NET Framework 2.0中的事务管理系统能够解决动态事务组合而导致的额外开销问题。它还提供了将多个不稳定资源转换为提交和回滚事务模型所需的架构。在下面的内容中将介绍.NET 2.0中与事务有关的轻量级事务管理、显式事务、TransactionScope类和自动化事务。

轻量级事务管理

    对于发生在单个应用程序域中的事务,LTM是一种运行很快,非常便宜的资源管理器。LTM是框架中所有事务的起点,同时监视正在与事务交互的资源,以及根据需要登记更多健壮的事务管理器的服务。

    当事务性工作在进程外工作(例如开始修改数据库数据)时,LTM将自动使用支持可升级的单阶段登记(PSPE)的资源管理器模型。这是一种新的事务性架构,其理解LTM的“预付费”机制。如果没有可用的PSPE管理器,那么LTM会登记DTC。当然,多个远程数据源将被登记的DTC修改。当PSPE模型开始工作时,事务的执行将于ADO.NET 1.x的事务一致。读者可能会怀疑PSPE具有与ADO.NET事务一样的性能。当与多个数据库交互时,事务将自动提升到DTC。

    在.NET Framework 2.0中,使用SQL Server 2005时将自动获得PSPE事务。如果事务性工作与另一个服务器或者数据库交互,那么自动使用DTC。易失性事务自动参与PSPE,而不用调用DTC。

实现显式事务

    有时候,TransactionScope对象的默认隐式自动事务功能可能无法提供所需较好的控制级别。在这种情况下,可能需要人工创建事务,同时显式提交或者回滚事务。示例1显示使用CommittableTransaction类创建显式事务包括的步骤。

    例1:使用CommittableTransaction实现显式事务
<%@ Page Language="C#" %> 
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.Transactions" %>
<%@ Import Namespace="System.Web.Configuration" %>

<script runat="server">
void btnSave_Click(object sender, EventArgs e)
{
CommittableTransaction trans = new CommittableTransaction();
try
{
string connectionString = WebConfigurationManager.ConnectionStrings
["Mydatabase"].ConnectionString;
using (SqlConnection connection = new SqlConnection(connectionString))
{
string sql = "Insert into Production.ProductCategory(Name," +
"rowguid, ModifiedDate) Values(@Name, @rowguid, @ModifiedDate)";
// 打开连接,在事务范围中登记此连接
connection.Open();
SqlCommand command = new SqlCommand(sql, connection);
command.CommandType = CommandType.Text;
SqlParameter nameParam =
new SqlParameter("@Name", SqlDbType.NVarChar, 50);
nameParam.Value = txtCategoryName.Text;
command.Parameters.Add(nameParam);
SqlParameter guidParam = new SqlParameter("@rowguid",
SqlDbType.UniqueIdentifier);
guidParam.Value = System.Guid.NewGuid();
command.Parameters.Add(guidParam);
SqlParameter modifieDateParam = new SqlParameter("@ModifiedDate",
SqlDbType.DateTime);
modifieDateParam.Value = System.DateTime.Now;
command.Parameters.Add(modifieDateParam);
//在当前事务的范围中登记事务
connection.EnlistTransaction(trans);
command.ExecuteNonQuery();
// 如果每一个执行都成功,则提交事务
trans.Commit();
}
lblResult.Text = "Category is written successfully";
}
catch (Exception ex)
{
// 如果出现异常,则回滚事务
trans.Rollback();
lblResult.Text = "Exception is : " + ex.Message;
}
}
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Using Explicit Transactions using CommittableTransaction</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="lblCategoryName" runat="server"
Text="Category Name:" Width="179px"></asp:Label>
<asp:TextBox ID="txtCategoryName" runat="server" />&nbsp;
<asp:Button ID="btnSave" runat="server" Text="Save" Width="92px"
OnClick="btnSave_Click" />
<br /><br />
<asp:Label ID="lblResult" runat="server" Font-Bold="true"
Font-Size="Small" />
</div>
</form>
</body>
</html>
    在这种方法中,需要调用SqlConnection对象的EnlistTransaction()方法(传递CommittableTransaction对象作为参数),以便将SqlConnection对象与CommittableTransaction对象关联起来。一旦完成这个工作,然后就可以通过调用CommittableTransaction对象的Commit()和Rollback()方法,显式提交或者回滚事务。正如能够想象的,不推荐使用这种手动方法,因为当发生不同类型的异常时,可能会遇到一些无法回滚事务的风险。
0
相关文章