c# 事物处理
以下示例创建一个 OleDbConnection 和一个 OleDbTransaction。它还演示了如何使用 BeginTransaction、Commit 和 Rollback 方法。
public void RunOleDbTransaction(string myConnString)
{
OleDbConnection myConnection = new OleDbConnection(myConnString);
myConnection.Open();
OleDbCommand myCommand = myConnection.CreateCommand();
OleDbTransaction myTrans;
// Start a local transaction
myTrans = myConnection.BeginTransaction(IsolationLevel.ReadCommitted);
// Assign transaction object for a pending local transaction
myCommand.Connection = myConnection;
myCommand.Transaction = myTrans;
try
{
myCommand.CommandText = ""Insert into Region (RegionID, RegionDescription) VALUES (100, "'Description"')"";
myCommand.ExecuteNonQuery();
myCommand.CommandText = ""Insert into Region (RegionID, RegionDescription) VALUES (101, "'Description"')"";
myCommand.ExecuteNonQuery();
myTrans.Commit();
Console.WriteLine(""Both records are written to database."");
}
catch(Exception e)
{
try
{
myTrans.Rollback();
}
catch (OleDbException ex)
{
if (myTrans.Connection != null)
{
Console.WriteLine(""An exception of type "" + ex.GetType() +
"" was encountered while attempting to roll back the transaction."");
}
}
Console.WriteLine(""An exception of type "" + e.GetType() +
"" was encountered while inserting the data."");
Console.WriteLine(""Neither record was written to database."");
}
finally
{
myConnection.Close();
}
}
OleDbTransaction.Commit 方法
提交数据库事务。
public virtual void Commit();
OleDbTransaction.Rollback 方法
从挂起状态回滚事务。
public virtual void Rollback();
OleDbConnection.BeginTransaction 方法
开始数据库事务。
public OleDbTransaction BeginTransaction();
以当前的 IsolationLevel 值开始数据库事务。
public OleDbTransaction BeginTransaction(IsolationLevel);
IsolationLevel 枚举?
指定连接的事务锁定行为。 在执行事务时,.NET Framework 数据提供程序使用 IsolationLevel 值。在显式更改之前,IsolationLevel 保持有效,但是可以随时对它进行更改。新值在执行时使用,而不是在分析时使用。如果在事务期间更改,服务器的预期行为是,对其余所有语句应用新的锁定级别。
IsolationLevel成员 ReadCommitted
在正在读取数据时保持共享锁,以避免脏读,但是在事务结束之前可以更改数据,从而导致不可重复的读取或幻像数据。
OleDbConnection.CreateCommand 方法
创建和返回一个与 OleDbConnection 相关联的 OleDbCommand 对象。
public OleDbCommand CreateCommand();
OleDbCommand.Connection 属性
获取或设置 OleDbCommand 的此实例使用的 OleDbConnection。
public OleDbConnection Connection {get; set;}
如何在.NET中实现事务(1)
如何在.NET中实现事务机制呢? 通常可以使用2种方式: 直接写入到sql 中;使用ADO.NET 实现。下面依次作一下介绍:
方法1:直接写入到sql 中
使用 BEGIN TRANS, COMMIT TRANS, ROLLBACK TRANS 实现:
例如
BEGIN TRANS
DECLARE @orderDetailsError int, @productError int
DELETE FROM ""Order Details"" WHERE ProductID=42
SELECT @orderDetailsError = @@ERROR
DELETE FROM Products WHERE ProductID=42
SELECT @productError = @@ERROR
IF @orderDetailsError = 0 AND @productError = 0
COMMIT TRANS
ELSE
ROLLBACK TRANS
这种方法比较简单,具体可以查阅相关sql server 帮助
方法2 :使用ADO.NET 实现,使用这种方式的优点是可以在中间层来管理事务,当然你也可以选择在数据层来实现。
SqlConnection 和OleDbConnection 对象有一个 BeginTransaction 方法,它可以返回 SqlTransaction 或者OleDbTransaction 对象。而且这个对象有 Commit 和 Rollback 方法来管理事务,具体例子如下:
cnNorthwind.Open()
Dim trans As SqlTransaction = cnNorthwind.BeginTransaction()
Dim cmDel As New SqlCommand()
cmDel.Connection = cnNorthwind
cmDel.Transaction = trans
Try
cmDel.CommandText = _
""DELETE [Order Details] WHERE ProductID = 42""
cmDel.ExecuteNonQuery()
cmDel.CommandText = ""DELETE Products WHERE ProductID = 42""
cmDel.ExecuteNonQuery()
trans.Commit()
Catch Xcp As Exception
trans.Rollback()
Finally
cnNorthwind.Close()
End Try
Ok,通过上面的例子可以实现与方法1同样的效果。
并发问题:
如果没有锁定且多个用户同时访问一个数据库,则当他们的事务同时使用相同的数据时可能会发生问题。并发问题包括: 丢失或覆盖更新,未确认的相关性(脏读),不一致的分析(非重复读),幻像读。但是如何来避免数据读取时脏读等问题出现呢?
二、事务实例
using(SqlTransaction trans = conn.BeginTransaction())
{
try
{
//循环进行信息的插入
for(int count = 0; count < applyInfo.Length; count ++)
{
//声明参数并赋值
SqlParameter[] parms =
{ Database.MakeInParam (""@Stu_ID"",System.Data.SqlDbType.VarChar,11,applyInfocount].StuID),
Database.MakeInParam""@Bank_Name"",System.Data.SqlDbType.VarChar,50,applyInfo[count].BankName), Database.MakeInParam""@Apply_Loan_Money"",System.Data.SqlDbType.Money,8,applyInfo[count].ApplyLoanMoney), Database.MakeInParam(""@Apply_Loan_Year"",System.Data.SqlDbType.VarChar,20,applyInfo[count].ApplyLoanYear), Database.MakeInParam""@Apply_Year"",System.Data.SqlDbType.Char,6,applyInfo[count].ApplyYear), Database.MakeInParam(""@Apply_Length"",System.Data.SqlDbType.Int,4,applyInfo[count].ApplyLength), Database.MakeInParam(""@Apply_Pass"",System.Data.SqlDbType.Char,1,applyInfo[count].ApplyPass),
Database.MakeInParam(""@Apply_Remark"",System.Data.SqlDbType.VarChar,100,applyInfo[count].ApplyRemark)
};
//执行新增操作
SqlHelper.ExecuteNonQuery(trans,CommandType.StoredProcedure, ""ApplyInfo_Create"", parms);
}
//未出现错误,则提交事务
trans.Commit();
return true;
}
catch(Exception ex)
{
//出错则回滚
trans.Rollback();
throw ex;
}
}
四、注意事项
事务的定义必须在连接打开后,提交必须在关闭以前
使用事务时必须即是把事务添加到sqlCommand中去。
另外,以下是一段在LINQ中实现的事务:
if (ctx.Connection != null) ctx.Connection.Open(); |
以下示例创建一个 OleDbConnection 和一个 OleDbTransaction。它还演示了如何使用 BeginTransaction、Commit 和 Rollback 方法。
public void RunOleDbTransaction(string myConnString)
{
OleDbConnection myConnection = new OleDbConnection(myConnString);
myConnection.Open();
OleDbCommand myCommand = myConnection.CreateCommand();
OleDbTransaction myTrans;
// Start a local transaction
myTrans = myConnection.BeginTransaction(IsolationLevel.ReadCommitted);
// Assign transaction object for a pending local transaction
myCommand.Connection = myConnection;
myCommand.Transaction = myTrans;
try
{
myCommand.CommandText = ""Insert into Region (RegionID, RegionDescription) VALUES (100, "'Description"')"";
myCommand.ExecuteNonQuery();
myCommand.CommandText = ""Insert into Region (RegionID, RegionDescription) VALUES (101, "'Description"')"";
myCommand.ExecuteNonQuery();
myTrans.Commit();
Console.WriteLine(""Both records are written to database."");
}
catch(Exception e)
{
try
{
myTrans.Rollback();
}
catch (OleDbException ex)
{
if (myTrans.Connection != null)
{
Console.WriteLine(""An exception of type "" + ex.GetType() +
"" was encountered while attempting to roll back the transaction."");
}
}
Console.WriteLine(""An exception of type "" + e.GetType() +
"" was encountered while inserting the data."");
Console.WriteLine(""Neither record was written to database."");
}
finally
{
myConnection.Close();
}
}
OleDbTransaction.Commit 方法
提交数据库事务。
public virtual void Commit();
OleDbTransaction.Rollback 方法
从挂起状态回滚事务。
public virtual void Rollback();
OleDbConnection.BeginTransaction 方法
开始数据库事务。
public OleDbTransaction BeginTransaction();
以当前的 IsolationLevel 值开始数据库事务。
public OleDbTransaction BeginTransaction(IsolationLevel);
IsolationLevel 枚举?
指定连接的事务锁定行为。 在执行事务时,.NET Framework 数据提供程序使用 IsolationLevel 值。在显式更改之前,IsolationLevel 保持有效,但是可以随时对它进行更改。新值在执行时使用,而不是在分析时使用。如果在事务期间更改,服务器的预期行为是,对其余所有语句应用新的锁定级别。
IsolationLevel成员 ReadCommitted
在正在读取数据时保持共享锁,以避免脏读,但是在事务结束之前可以更改数据,从而导致不可重复的读取或幻像数据。
OleDbConnection.CreateCommand 方法
创建和返回一个与 OleDbConnection 相关联的 OleDbCommand 对象。
public OleDbCommand CreateCommand();
OleDbCommand.Connection 属性
获取或设置 OleDbCommand 的此实例使用的 OleDbConnection。
public OleDbConnection Connection {get; set;}
如何在.NET中实现事务(1)
如何在.NET中实现事务机制呢? 通常可以使用2种方式: 直接写入到sql 中;使用ADO.NET 实现。下面依次作一下介绍:
方法1:直接写入到sql 中
使用 BEGIN TRANS, COMMIT TRANS, ROLLBACK TRANS 实现:
例如
BEGIN TRANS
DECLARE @orderDetailsError int, @productError int
DELETE FROM ""Order Details"" WHERE ProductID=42
SELECT @orderDetailsError = @@ERROR
DELETE FROM Products WHERE ProductID=42
SELECT @productError = @@ERROR
IF @orderDetailsError = 0 AND @productError = 0
COMMIT TRANS
ELSE
ROLLBACK TRANS
这种方法比较简单,具体可以查阅相关sql server 帮助
方法2 :使用ADO.NET 实现,使用这种方式的优点是可以在中间层来管理事务,当然你也可以选择在数据层来实现。
SqlConnection 和OleDbConnection 对象有一个 BeginTransaction 方法,它可以返回 SqlTransaction 或者OleDbTransaction 对象。而且这个对象有 Commit 和 Rollback 方法来管理事务,具体例子如下:
cnNorthwind.Open()
Dim trans As SqlTransaction = cnNorthwind.BeginTransaction()
Dim cmDel As New SqlCommand()
cmDel.Connection = cnNorthwind
cmDel.Transaction = trans
Try
cmDel.CommandText = _
""DELETE [Order Details] WHERE ProductID = 42""
cmDel.ExecuteNonQuery()
cmDel.CommandText = ""DELETE Products WHERE ProductID = 42""
cmDel.ExecuteNonQuery()
trans.Commit()
Catch Xcp As Exception
trans.Rollback()
Finally
cnNorthwind.Close()
End Try
Ok,通过上面的例子可以实现与方法1同样的效果。
并发问题:
如果没有锁定且多个用户同时访问一个数据库,则当他们的事务同时使用相同的数据时可能会发生问题。并发问题包括: 丢失或覆盖更新,未确认的相关性(脏读),不一致的分析(非重复读),幻像读。但是如何来避免数据读取时脏读等问题出现呢?
二、事务实例
using(SqlTransaction trans = conn.BeginTransaction())
{
try
{
//循环进行信息的插入
for(int count = 0; count < applyInfo.Length; count ++)
{
//声明参数并赋值
SqlParameter[] parms =
{ Database.MakeInParam (""@Stu_ID"",System.Data.SqlDbType.VarChar,11,applyInfocount].StuID),
Database.MakeInParam""@Bank_Name"",System.Data.SqlDbType.VarChar,50,applyInfo[count].BankName), Database.MakeInParam""@Apply_Loan_Money"",System.Data.SqlDbType.Money,8,applyInfo[count].ApplyLoanMoney), Database.MakeInParam(""@Apply_Loan_Year"",System.Data.SqlDbType.VarChar,20,applyInfo[count].ApplyLoanYear), Database.MakeInParam""@Apply_Year"",System.Data.SqlDbType.Char,6,applyInfo[count].ApplyYear), Database.MakeInParam(""@Apply_Length"",System.Data.SqlDbType.Int,4,applyInfo[count].ApplyLength), Database.MakeInParam(""@Apply_Pass"",System.Data.SqlDbType.Char,1,applyInfo[count].ApplyPass),
Database.MakeInParam(""@Apply_Remark"",System.Data.SqlDbType.VarChar,100,applyInfo[count].ApplyRemark)
};
//执行新增操作
SqlHelper.ExecuteNonQuery(trans,CommandType.StoredProcedure, ""ApplyInfo_Create"", parms);
}
//未出现错误,则提交事务
trans.Commit();
return true;
}
catch(Exception ex)
{
//出错则回滚
trans.Rollback();
throw ex;
}
}
四、注意事项
事务的定义必须在连接打开后,提交必须在关闭以前
使用事务时必须即是把事务添加到sqlCommand中去。
另外,以下是一段在LINQ中实现的事务:
if (ctx.Connection != null) ctx.Connection.Open(); |