事務是一個原子的工作單位,必須完整的完成單位裡的所有工作,要麼全部執行,要麼全部都不執行 。如果提交事務,則事務執行成功;如果回滾事務,則事務執行失敗。 事務具備4個基本特性--ACID(原 子性、一致性、孤立性和持久性)。
在Linq to SQL中,有三種方法創建事務:
如果沒有指定任何事務,那麼當調用SubmitChanges方法時,DataContext會默認創建一個事務。
使用TransactionScope創建輕量級事務
給DataContext的Transaction屬性指定事務
下面我用代碼分別來說明這幾種創建事務的方法,以Northwind數據庫為例,先來看看直接使用 SubmitChanges:
NorthwindDataContext ctx = new NorthwindDataContext();
Customer c1 = new Customer { CustomerID = "TESTA", CompanyName = "testa's company" };
Customer c2 = new Customer { CustomerID = "TESTBC", CompanyName = "testb's company" };
ctx.Customers.Add(c1);
ctx.Customers.Add(c2);
ctx.SubmitChanges();
上面這段代碼中,先創建了兩個Customer對象然後添加到DataContext裡面,其中的c2的CustomerID賦 值為"TESTBC",長度為六個字符,而數據庫中該字段約束為5個字符長度,這樣在SubmitChanges的時候應 該會有異常拋出。果然在執行的時候拋出了SqlException,提示字符將被截斷。
再通過Sql Server管理器可以看到上面這兩條數據都沒有被插入到數據庫中。通過Reflector可以發現 在SubmitChanges的時候,Linq to SQL默認創建了一個孤立級別為Read Committed的事務(它表示已提交 的更新在事務間是可見的,具體有哪些孤立級別可以參考ADO.NET相關資料):
public virtual void SubmitChanges(ConflictMode failureMode)
{
...
transaction = this.provider.Connection.BeginTransaction (IsolationLevel.ReadCommitted);
this.provider.Transaction = transaction;
}
如果不想使用默認的事務設置,比如想改變事務的孤立級別,我們可以給DataContext的Transaction屬 性賦值,以此使用自定義的事務。
ctx.Transaction = ctx.Connection.BeginTransaction (System.Data.IsolationLevel.Serializable);
try
{
ctx.SubmitChanges();
ctx.Transaction.Commit();
}
catch
{
ctx.Transaction.Rollback();
throw;
}
finally
{
ctx.Transaction = null;
}
最後一種方式是通過TransactionScope創建輕量級事務,就像在ADO.NET中使用一樣:
using (TransactionScope scope = new TransactionScope())
{
ctx.SubmitChanges();
scope.Complete();
}
上面的例子看起來似乎多此一舉,因為在SubmitChanges中會創建默認的事務,但是改成下面這樣,就 只能使用自定義的事務了:
using (TransactionScope scope = new TransactionScope())
{
ctx.ExecuteCommand("exec ....");
ctx.ExecuteCommand("exec ....");
ctx.ExecuteCommand("exec ....");
ctx.SubmitChanges();
scope.Complete();
}
不管ExecuteCommand裡面執行了哪些操作,我們都能夠指明這些行為和SubmitChanges處於同一個事務 中。