• <fieldset id="8imwq"><menu id="8imwq"></menu></fieldset>
  • <bdo id="8imwq"><input id="8imwq"></input></bdo>
    最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
    問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
    當前位置: 首頁 - 科技 - 知識百科 - 正文

    解析ABP框架中的事務處理和工作單元

    來源:懂視網 責編:小采 時間:2020-11-27 22:37:23
    文檔

    解析ABP框架中的事務處理和工作單元

    解析ABP框架中的事務處理和工作單元:通用連接和事務管理方法 連接和事務管理是使用數據庫的應用程序最重要的概念之一。當你開啟一個數據庫連接,什么時候開始事務,如何釋放連接...諸如此類的。 正如大家都知道的.Net使用連接池(connection pooling)。因此,創建一個連接實際上是從連接池中取得
    推薦度:
    導讀解析ABP框架中的事務處理和工作單元:通用連接和事務管理方法 連接和事務管理是使用數據庫的應用程序最重要的概念之一。當你開啟一個數據庫連接,什么時候開始事務,如何釋放連接...諸如此類的。 正如大家都知道的.Net使用連接池(connection pooling)。因此,創建一個連接實際上是從連接池中取得

    通用連接和事務管理方法
    連接和事務管理是使用數據庫的應用程序最重要的概念之一。當你開啟一個數據庫連接,什么時候開始事務,如何釋放連接...諸如此類的。

    正如大家都知道的,.Net使用連接池(connection pooling)。因此,創建一個連接實際上是從連接池中取得一個連接,會這么做是因為創建新連接會有成本。如果沒有任何連接存在于連接池中,一個新的連接對象會被創建并且添加到連接池中。當你釋放連接,它實際上是將這個連接對象送回到連接池。這并不是實際意義上的釋放。這個機制是由.Net所提供的。因此,我們應該在使用完之后釋放掉連接對象。這就是最佳實踐。

    在應用程序中,有兩個通用的方來創建/釋放一個數據庫連接:

    第一個方法:在Web請求到達的時候,創建一個連接對象。(Application_BeginRequest這個位于global.asax中的事件),使用同一個連接對象來處理所有的數據庫操作,并且在請求結束的時候關閉/釋放這個連接 (Application_EndRequest事件)。

    這是個簡易但卻沒效率的方法,原因:

  • 或許這個Web請求不需要操作數據庫,但是連接卻會開啟。這對于連接池來說是個毫無效率的使用方式。
  • 這可能會讓Web請求的運行時間變長,并且數據庫操作還會需要一些執行。這也是一種沒效率的連接池使用方式。
  • 這對于Web應用來說是可行的。如果你的應用程序是Widnows Service,這可能就無法被實現了。
  • 同樣的這是一個使用事務式的數據庫操作最佳場景。如果有一個操作發生失敗,所有的操作都會回滾。因為事務會鎖住數據庫中的一些數據列(事件數據表),它必定要是短暫的。
  • 第二個方法: 創建一個連接當需要的時候(只要在使用它之前)并且釋放它在使用它之后。這是相當高效的,但是就得乏味而且反復的去進行(創建/釋放連接)。

    ABP的連接和事務管理
    ABP綜合上述兩個連接管理的方法,并且提供一個簡單而且高效的模型。

    1.倉儲類(Repository classes)

    倉儲是主要的數據庫操作的類。ABP開啟了一個數據庫連接并且在進入到倉儲方法時會啟用一個事務。因此,你可以安全地使用連接于倉儲方法中。在倉儲方法結束后,事務會被提交并且會釋放掉連接。假如倉儲方法拋出任何異常,事務會被回滾并且釋放掉連接。在這個模式中,倉儲方法是單元性的(一個工作單元unit of work)。ABP在處理上述那些動作都是全自動的。在這里,有一個簡單的倉儲:

    public class ContentRepository : NhRepositoryBase<Content>, IContentRepository
    {
     public List<Content> GetActiveContents(string searchCondition)
     {
     var query = from content in Session.Query<Content>()
     where content.IsActive && !content.IsDeleted
     select content;
    
     if (string.IsNullOrEmpty(searchCondition))
     {
     query = query.Where(content => content.Text.Contains(searchCondition));
     }
    
     return query.ToList();
     }
    }
    
    
     

    這個示例使用NHibernate作為ORM框架。如上所示,不需要撰寫任何數據庫連接操作(NHibernate中的Session)的程序代碼。

    假如倉儲方法調用另一個倉儲方法(一般來說,若工作單元方法調用另一個工作單元的方法),都使用同一個連接和事務。第一個被調用到的倉儲方法負責管理連接和事務,而其余被它調用的倉儲方法則只單純使用不管理。

    2.應用服務(Application service classes)

    一個應用服務的方法也被考慮使用工作單元。如果我們擁有一個應用服務方法如下:

    public class PersonAppService : IPersonAppService
    {
     private readonly IPersonRepository _personRepository;
     private readonly IStatisticsRepository _statisticsRepository;
    
     public PersonAppService(IPersonRepository personRepository, IStatisticsRepository statisticsRepository)
     {
     _personRepository = personRepository;
     _statisticsRepository = statisticsRepository;
     }
    
     public void CreatePerson(CreatePersonInput input)
     {
     var person = new Person { Name = input.Name, EmailAddress = input.EmailAddress };
     _personRepository.Insert(person);
     _statisticsRepository.IncrementPeopleCount();
     }
    }
    
    
     

    在CreatePerson方法中,我們新增一個person使用person倉儲并且使用statistics倉儲增加總people數量。兩個倉儲共享同一個連接和事務于這個例子中,因為這是一個應用服務的方法。ABP開啟一個數據庫連接并且開啟一個事務于進入到CreationPerson這個方法,若沒有任何異常拋出,接著提交這個事務于方法結尾時,若有異常被拋出,則會回滾這個事務。在這種機制下,所有數據庫的操作在CreatePerson中,都成了單元性的了(工作單元)。

    3.工作單元(Unit of work)

    工作單元在后臺替倉儲和應用服務的方法工作。假如你想要控制數據庫的連接和事務,你就需要直接操作工作單元。下面有兩個直接使用的示例:

    首要且最好的使用UnitOfWorkAttribute的方式如下:

    [UnitOfWork]
    public void CreatePerson(CreatePersonInput input)
    {
     var person = new Person { Name = input.Name, EmailAddress = input.EmailAddress };
     _personRepository.Insert(person);
     _statisticsRepository.IncrementPeopleCount();
    }
    

    因此,CreatePerson方法轉變成工作單元并且管理數據庫連接和事務,兩個倉儲對象都使用相同的工作單元。要注意,假如這是應用服務的方法則不需要添加UnitOfWork屬性,見工作單元方法:第三章,3.3.5。

    第二個示例是使用IUnitOfWorkManager.Begin(...)方法如下所示:

     public class MyService
    {
     private readonly IUnitOfWorkManager _unitOfWorkManager;
     private readonly IPersonRepository _personRepository;
     private readonly IStatisticsRepository _statisticsRepository;
    
     public MyService(IUnitOfWorkManager unitOfWorkManager, IPersonRepository personRepository, IStatisticsRepository statisticsRepository)
     {
     _unitOfWorkManager = unitOfWorkManager;
     _personRepository = personRepository;
     _statisticsRepository = statisticsRepository;
     }
    
     public void CreatePerson(CreatePersonInput input)
     {
     var person = new Person { Name = input.Name, EmailAddress = input.EmailAddress };
    
     using (var unitOfWork = _unitOfWorkManager.Begin())
     {
     _personRepository.Insert(person);
     _statisticsRepository.IncrementPeopleCount();
    
     unitOfWork.Complete();
     }
     }
    }
    
    
    你可以注入并且使用IUnitOfWorkManager,如上所示。因此,你可以創建更多的有限范圍 (limited scope)的工作單元。在這個機制中,你通??梢允謩诱{用Complete方法。如果你不調用,事務會回滾并且所有的異常都不會被儲存。Begin方法被重寫從而設置工作單元的選項。

    這很棒,不過除非你有很好的理由,否則還是少用UnitOfWork屬性。

    工作單元
    1.禁用工作單元(Disabling unit of work)

    你或許會想要禁用應用服務方法的工作單元(因為它默認是啟用的)。要想做到這個,使用UnitOfWorkAttribute的IsDisabled屬性。示例如下:

    [UnitOfWork(IsDisabled = true)]
    public virtual void RemoveFriendship(RemoveFriendshipInput input)
    {
     _friendshipRepository.Delete(input.Id);
    }
    

     平常時, 你不會需要這么做,這是因為應用服務的方法都應該是單元性且通常是使用數據庫。在有些情況下,你或許會想要禁用應用服務的工作單元:

    (1)你的方法不需要任何數據庫操作且你不想要開啟那些不需要的數據庫連接
    (2)你想要使用工作單元于UnitOfWorkScope類的有限范圍內,如上所述
    注意,如果工作單元方法調用這個RemoveFriendship方法,禁用被忽略且它和調用它的方法使用同一個工作單元。因此,使用禁用這個功能要很小心。同樣地,上述程序代碼工作的很好,因為倉儲方法默認即為工作單元。

    2.無事務的工作單元(Non-transactional unit of work)

    工作單元默認上是具事務性的(這是它的天性)。因此,ABP啟動/提交/回滾一個顯性的數據庫等級的事務。在有些特殊案例中,事務可能會導致問題,因為它可能會鎖住有些數據列或是數據表于數據庫中。在此這些情境下, 你或許會想要禁用數據庫等級的事務。UnitOfWork屬性可以從它的建構子中取得一個布爾值來讓它如非事務型工作單元般工作著。示例為:

     [UnitOfWork(false)]
    public GetTasksOutput GetTasks(GetTasksInput input)
    {
     var tasks = _taskRepository.GetAllWithPeople(input.AssignedPersonId, input.State);
     return new GetTasksOutput
     {
     Tasks = Mapper.Map<List<TaskDto>>(tasks)
     };
    }
    

    建議可以這么做[UnitOfWork(isTransaction:false)]。(具有可讀性并且明確)。

    注意,ORM框架(像是NHibernate和EntityFramework)會在單一命令中于內部進行數據儲存。假設你更新了一些的實體于非事務的UoW。即便于這個情境下所有的更新都會于單一數據庫命令的工作單元尾部完成。但是,如果你直接執行SQL查詢,它會立即被執行。

    這里有一個非事務性UoW的限制。如果你已經位于事務性UoW區域內,設定isTransactional為false這個動作會被忽略。

    使用非事務性UoW要小心,因為在大多數的情況下,數據整合應該是具事務性的。如果你的方法只是讀取數據,不改變數據,那么當然可以采用非事務性。

    3.工作單元調用其它工作單元(A unit of work method calls another)

    若工作單元方法(一個貼上UnitOfWork屬性標簽的方法)調用另一個工作單元方法,他們共享同一個連接和事務。第一個方法管理連接,其它的方法只是使用它。這在所有方法都執行在同一個線程下是可行的(或是在同一個Web請求內)。實際上,當工作單元區域開始,所有的程序代碼都會在同一個線程中執行并共享同一個連接事務,直到工作單元區域終止。這對于使用UnitOfWork屬性和UnitOfWorkScope類來說都是一樣的。如果你創建了一個不同的線程/任務,它使用自己所屬的工作單元。

    自動化的saving changes (Automatically saving changes)

    當我們使用工作單元到方法上,ABP自動的儲存所有變化于方法的末端。假設我們需要一個可更新person名稱的方法:

     [UnitOfWork]
     public void UpdateName(UpdateNameInput input) {
     var person = _personRepository.Get(input.PersonId);
     person.Name = input.NewName;
     }
    

    就這樣,名稱就被修改了!我們甚至沒有調用_personRepository.Update方法。ORM框架會持續追蹤實體所有的變化于工作單元內,且反映所有變化到數據庫中。

    注意,這不需要在應用服務聲明UnitOfWork,因為它們默認就是采用工作單元。

    4.倉儲接口的GetAll()方法(IRepository.GetAll())

    當你在倉儲方法外調用GetAll方法, 這必定得有一個開啟狀態的數據庫連接,因為它返回IQueryable類型的對象。這是需要的,因為IQueryable延遲執行。它并不會馬上執行數據庫查詢,直到你調用ToList()方法或在foreach循環中使用IQueryable(或是存取被查詢結果集的情況下)。因此,當你調用ToList()方法,數據庫連接必需是啟用狀態。示例:

    [UnitOfWork]
    public SearchPeopleOutput SearchPeople(SearchPeopleInput input)
    {
     //Get IQueryable<Person>
     var query = _personRepository.GetAll();
    
     //Add some filters if selected
     if (!string.IsNullOrEmpty(input.SearchedName))
     {
     query = query.Where(person => person.Name.StartsWith(input.SearchedName));
     }
    
     if (input.IsActive.HasValue)
     {
     query = query.Where(person => person.IsActive == input.IsActive.Value);
     }
    
     //Get paged result list
     var people = query.Skip(input.SkipCount).Take(input.MaxResultCount).ToList();
    
     return new SearchPeopleOutput { People = Mapper.Map<List<PersonDto>>(people) };
    }
    
    

    在這里,SearchPeople方法必需是工作單元,因為IQueryable在被調用ToList()方法于方法本體內,并且數據庫連接必須于IQueryable.ToList()被執行時開啟。

    一如GetAll()方法,如果需要數據庫連接且沒有倉儲的情況下,你就必須要使用工作單元。注意,應用服務方法默認就是工作單元。

    5.工作單元屬性的限制(UnitOfWork attribute restrictions)

    在下面情境下你可以使用UnitOfWork屬性標簽:

    (1)類所有public或public virtual這些基于界面的方法(像是應用服務是基于服務界面)
    (2)自我注入類的public virtual方法(像是MVC Controller和Web API Controller)
    (3)所有protected virtual方法。
    建議將方法標示為virtual。你無法應用在private方法上。因為,ABP使用dynamic proxy來實現,而私有方法就無法使用繼承的方法來實現。當你不使用依賴注入且自行初始化類,那么UnitOfWork屬性(以及任何代理)就無法正常運作。

    選項
    有許多可以用來控制工作單元的選項。

    首先,我們可以在startup configuration中改變所有工作單元的所有默認值。這通常是用了我們模塊中的PreInitialize方法來實現。

     

    public class SimpleTaskSystemCoreModule : AbpModule
    {
     public override void PreInitialize()
     {
     Configuration.UnitOfWork.IsolationLevel = IsolationLevel.ReadCommitted;
     Configuration.UnitOfWork.Timeout = TimeSpan.FromMinutes(30);
     }
    
     //...other module methods
    }
    
    

    方法
    工作單元系統運作是無縫且不可視的。但是,在有些特例下,你需要調用它的方法。

    SaveChanges:

    ABP儲存所有的變化于工作單元的尾端,你不需要做任何事情。但是,有些時候,你或許會想要在工作單元的過程中就儲存所有變化。在這個案例中,你可以注入IUnitOfWorkManager并且調用IUnitOfWorkManager.Current.SaveChanges()方法。示例中以Entity Framework在儲存變化時取得新增實體的Id。注意,當前工作單元是具事務性的,所有在事務中的變化會在異常發生時都被回滾,即便是已調用SaveChange。

    事件
    工作單元具有Completed/Failed/Disposed事件。你可以注冊這些事件并且進行所需的操作。注入IUnitOfWorkManager并且使用IUnitOfWorkManager.Current 屬性來取得當前已激活的工作單元并且注冊它的事件。

    你或許會想要執行有些程序代碼于當前工作單元成功地完成。示例:

     

    public void CreateTask(CreateTaskInput input)
    {
     var task = new Task { Description = input.Description };
    
     if (input.AssignedPersonId.HasValue)
     {
     task.AssignedPersonId = input.AssignedPersonId.Value;
    
     _unitOfWorkManager.Current.Completed += (sender, args) => { /* TODO: Send email to assigned person */ };
     }
    
     _taskRepository.Insert(task);
    }
    

    聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

    解析ABP框架中的事務處理和工作單元

    解析ABP框架中的事務處理和工作單元:通用連接和事務管理方法 連接和事務管理是使用數據庫的應用程序最重要的概念之一。當你開啟一個數據庫連接,什么時候開始事務,如何釋放連接...諸如此類的。 正如大家都知道的.Net使用連接池(connection pooling)。因此,創建一個連接實際上是從連接池中取得
    推薦度:
    • 熱門焦點

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 国模和精品嫩模私拍视频| 精品黑人一区二区三区| 亚洲麻豆精品国偷自产在线91| 国产精品九九久久免费视频| 3级黄性日本午夜精品| 精品国产日产一区二区三区| 国产午夜精品视频| 久久精品国产亚洲沈樵| 51久久夜色精品国产| 久久夜色精品国产网站| 国产精品美女久久久久久2018| 91精品视频网站| 大胸国产精品视频| 久久久WWW免费人成精品| 正在播放国产精品每日更新| 91久久精品国产91性色也| 国产成人久久精品一区二区三区 | 97久久精品午夜一区二区| 亚洲日韩精品无码专区网址| 久久香综合精品久久伊人| 欧美精品亚洲精品日韩精品| 老司机午夜精品视频资源| 亚洲第一区精品观看| 国产精品黄网站| 国产精品无套内射迪丽热巴| 无码精品人妻一区二区三区漫画| 国产精品亚洲精品| 国产精品视频二区不卡| 久久精品中文騷妇女内射| 久久国产精品-国产精品| 1000部精品久久久久久久久| 国内精品欧美久久精品| www夜片内射视频日韩精品成人| 欧美精品手机在线播放| 国产亚洲精品xxx| 2022年国产精品久久久久| 国产精品内射后入合集| 国产欧美日韩综合精品一区二区| 精品无码国产一区二区三区AV| 久久99精品国产自在现线小黄鸭| 久久影院综合精品|