業務層,你不能知道數據庫的實現細節
這個話題也是網上談論的非常多的,你的業務層是否會包含你的數據層的相關架構技術,如,你的數據層的持久化通過EF來實現,那么你的業務層是否也應該引入EntityFrameworks程序集?占占還是會告訴你,不應該,因為這樣會使你的業務不再是純粹的業務,它會依賴由你的數據層的持久化實現的技術,這是不對的,我們需要把業務層解藕出來,只有這樣,你的數據層在進行技術切換時,業務層才不會受到影響,當然,這是理所當然的,如果你的數據庫換技術了,還會影響到你的業務層,那么,你這個架構本身就是失敗的!
我的EF架構失敗了
在我的EF架構里,業務層使用了數據層實現的entityframeworks程序集,它知道了太多持久化的方式,所以,它是失敗的,你失敗,因為你讓我無法簡單的從一種ORM切換到別一種ORM。
失敗的原因,可以理解
之所以在業務層引用entityframeworks,原因是“事務”,為了保證數據一致性,我們會在程序中加入事務塊,而有時,sql2005來說,它會將本地事務不可理解的提高為分布式事務,這對于系統來說,無疑是一種負擔,所以,我只能把這個事務塊進行重寫,重寫后使它不會觸發分布式事務,但同樣也出現了一個慘痛的代價,那就是,一個本地事務需要具體同一個“數據上下文”,即entityframeworks里的DbContext對象,所以,BLL層就這樣,依賴了EF,失敗是可以理解的。
理想的事務應該放在數據層(基礎設施層,持久化層)
事務總是和數據庫相關,似乎與業務沒什么關系,而業務層也不應該知道你的數據采用什么樣的方式進行一致性的處理,一可以用SqlTransaction,也可以用TransactionScope,或者用第三方的事務組件,但歸根到底,它們都是與持久化方式(ado.net的SqlTransaction,ef,linq2sql的TransactionScope)有關的,所以,放在業務層是絕對杜絕的,以下是從《Microsoft .NET企業級應用架構設計》一書中選自的一段話
數據訪問層的4種主要職責:持久化、查詢、管理事務、維護并發
SQL2008是美麗的
當SQLSERVER升級到2008,它似乎查覺到了什么,可能是一種壞味道,一種代碼的壞味道,在SQL2005里,一個語句被發到SQL端,會reset一個SQL鏈接,正是一個reset導致我們的net把這個過程當成是一個分布式事務來處理,而SQL2008里,如果你的數據庫是一個,那個它就會認為,你的這個過程是一個Local session的過程,即,本地會話,本地事務!
我的貢獻
下面貢獻一下我的SQL2005同一上下文不觸發MSDTC的解決方案代碼
/// <summary> /// Author:zhang.zhanling /// 同步文章:http://www.cnblogs.com/lori/p/3455393.html /// 對TransactionScope,讓它對同一個數據庫不產生msdtc服務 /// 環境:sql2005,sql2008本身已經解決了這個問題 /// </summary> public class TransactionScopeNoMsdtc { /// <summary> /// 產生包裹事務 /// 維持一個connection連接對象 /// </summary> /// <param name="db">數據上下文</param> /// <param name="isOutest">是否為最外層,默認為false</param> /// <param name="action">處理代碼塊</param> public static void UsingNoMsdtc(IUnitOfWork db, bool isOutest, Action action) { var objectContext = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)db).ObjectContext; try { if (objectContext.Connection.State == System.Data.ConnectionState.Closed) objectContext.Connection.Open(); using (TransactionScope trans = new TransactionScope()) { action(); trans.Complete(); } } finally { if (isOutest)//如果是最外層事務,再將連接關閉!內部事務與外部事務需要共用一個Connection的連接 objectContext.Connection.Close(); //只能關閉,不能dispose,因為dispose之后,上下文就無法得到鏈接串了 } } /// <summary> /// 產生包裹事務,它不是最外層的,如果是最外層的需要調用其它重載 /// </summary> /// <param name="db"></param> /// <param name="action"></param> public static void UsingNoMsdtc(IUnitOfWork db, Action action) { UsingNoMsdtc(db, false, action); } }
文章列表