Asp.net core 學習筆記 ( ef core transaction scope & change level )


更新: 2020-02-21 

補上一些憂慮

public async Task Inside()
{
    using var scope = SqlCommonMethod.CreateTransactionScope();
    await SqlCommonMethod.SetIsolationLevel(Db, IsolationLevel.Serializable); // 開啟高級別鎖
    var countries = await Db.Countries.ToListAsync(); // counties 表被高級鎖了
    await SqlCommonMethod.SetIsolationLevel(Db, IsolationLevel.ReadCommitted); // 設置回普通鎖, 不然接下來都會一直是高級鎖
    await Inside2();
    scope.Complete(); // 這里的 complete 結束並不會解鎖, 會一直等到最外面的 scope 被釋放, 符合邏輯
}

public async Task Inside2()
{
    using var scope = SqlCommonMethod.CreateTransactionScope();
    var countries = await Db.States.ToListAsync(); // // states 表被普通鎖了
    scope.Complete();
}

#region Simple test 
[HttpPost("simple-test")]
public async Task<IActionResult> SimpleTest()
{
    using (var scope = SqlCommonMethod.CreateTransactionScope())
    {
        await Inside();
        scope.Complete(); // 這里依然不會解鎖, 要等到 scope 釋放
    } 
    // 直到 using 結束才會解鎖 table 哦
    return Ok("ok");
}

總結 : 每次設置級別后最好是設置回去. 不然全場都會使用高級鎖. 

 

ef core 有 unit of work 的概念,當我們 save change 時會自動使用 transaction 確保更新的一致性. 隔離級別是默認的 read committed 不允許臟讀. 

但是呢, 有時候我們希望擁有更好的隔離級別, 比如 repeatable read, serializable 

那么就需要調用 database.beginTransaction 了. 

一旦需要自己控制 trans 麻煩就跟着來了。

比如在多個服務嵌套調用時, 如何共享 trans 呢 ? 

每個服務的 trans 級別也有可能是不同的.

如果我們單純使用 beginTransaction 那么需要在每個服務寫判斷,是否有 current transaction 做出不同的處理.   

在早期, 我們會用 transaction scope 作為業務級別的事務. 

transaction scope 非常強大, 可以跨庫, 分布式, 甚至可以鏈接 file system 

比如一個事務內做了數據庫修改,也創建了 file, 如果事務最終失敗,連 file 也可以 rollback 刪除掉. 

但自從 ef 出現后, 這個就變得大材小用了些. ef 也不推薦我們使用了 refer https://docs.microsoft.com/zh-cn/ef/ef6/saving/transactions?redirectedfrom=MSDN

 

 

ef core 在 2.1 的時候支持了 transactionscope 但是不支持分布式, 好像是不兼容 linux 所以去掉了.

但是在我說的這種情況下,使用它依然會讓代碼變得更好.

調用起來是這樣的

            using (var scope = new TransactionScope(
                scopeOption: TransactionScopeOption.Required,
                transactionOptions: new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.RepeatableRead },
                asyncFlowOption: TransactionScopeAsyncFlowOption.Enabled
            ))
            {
                try
                {
                 
                }
                catch (Exception ex)
                {
                    return BadRequest(ex.Message);
                }
                scope.Complete();
            }

默認隔離級別是 serializable. 

如果想在 service 里面嵌套, 那么重要設定 scopeOption 是 required 就可以了. 

它還有另外 2 個選擇, 1 個是 new 意思是另外開啟一個獨立的 trans, 再一個是 suppend 就是完全沒有 trans 無關.

有了這些就很靈活了,在不同 service 中我們可以去實現獨立或無關的事務處理. 

使用過程中需要注意幾件事情

 

 

嵌套 scope 需要使用同一種級別

這個挺麻煩的,通常不可能全部一個級別吧... 

目前沒有看到方法可以修改的,一個可能的辦法是直接調用 sql 語句 

set transaction isolation level read committed
set transaction isolation level repeatable read;
set transaction isolation level serializable

去設定它. 

這里順便說說 sql server 對於這一塊的處理. 

https://www.cnblogs.com/keatkeat/p/11830113.html

 

 

另一個要注意的是, 一定要設置 async enabled 如果 scope 內需要 async 的話

asyncFlowOption: TransactionScopeAsyncFlowOption.Enabled

 

refer : 

https://www.cnblogs.com/csdbfans/p/transactionscope.html

https://blog.csdn.net/qin_yu_2010/article/details/86150247

https://docs.microsoft.com/en-us/ef/core/saving/transactions

https://weblogs.thinktecture.com/pawel/2018/06/entity-framework-core-use-transactionscope-with-caution.html

https://www.cnblogs.com/taiyonghai/p/6047849.html

https://www.21cto.com/article/1075

https://www.codeproject.com/Articles/690136/All-About-TransactionScope#hBusinessTrans

https://codewala.net/2018/05/06/transactionscope-a-simple-way-to-handle-transactions-in-net/

https://docs.microsoft.com/zh-cn/dotnet/framework/data/transactions/implementing-an-implicit-transaction-using-transaction-scope

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM