ef core 有 unit of work 的概念,当我们 save change 时会自动使用 transaction 确保更新的一致性. 隔离级别是默认的 read committed 不允许脏读.
但是呢, 有时候我们希望拥有更好的隔离级别, 比如 repeatable read, serializable
那么就需要调用 database.beginTransaction 了.
一旦需要自己控制 trans 麻烦就跟着来了。
比如在多个服务之前, 如果共享 trans 呢 ?
每个服务的 trans 级别有可能是不同的呀.
在早期, 我们会有 transaction scope 作为业务级别的事务.
transaction scope 很非常强大, 可以跨库, 分布式, 甚至可以链接 file system
比如一个事务内做了数据库修改,也创建了 file, 如果事务最终失败,连 file 也可以 rollback 删除掉.
感觉用它有点大材小用了,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://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/