为啥当 Enlist=False 时 Sqlserver 在事务中登记?

Posted

技术标签:

【中文标题】为啥当 Enlist=False 时 Sqlserver 在事务中登记?【英文标题】:Why is Sqlserver enlisting in transaction when Enlist=False?为什么当 Enlist=False 时 Sqlserver 在事务中登记? 【发布时间】:2021-06-27 14:13:14 【问题描述】:

使用实体Framework 5(5.0.4)和本地SQL Server,为什么下面的代码没有在数据库中创建一行?

注意连接字符串中包含Enlist=False

using System;
using System.Transactions;
using Microsoft.EntityFrameworkCore;

namespace EfTransaction

    public class Program
    
        public static void Main()
        
            var scope = new TransactionScope();
            var ctx = new MyDbContext();
            var eObj = new MyEntityObject  Name = "My New Object" ;

            ctx.Set<MyEntityObject>().Add(eObj);
            
            ctx.SaveChanges();
            
            scope.Dispose();

            Console.WriteLine("Done");
        
    
    
    public class MyDbContext : DbContext
    
        public DbSet<MyEntityObject> MyObjects  get; set; 

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        
            optionsBuilder.UseSqlServer(
                "Server=.;Initial Catalog=MyDb;User Id=sa;Password=hunter2;Integrated Security=false;MultipleActiveResultSets=true;Enlist=False;");
        

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        
            modelBuilder.Entity<MyEntityObject>().HasKey(x => x.Name);
        
    
    
    public class MyEntityObject
    
        public string Name  get; set; 
    

【问题讨论】:

【参考方案1】:

SqlConnection 连接字符串参数控制 System.Transaction 由 SqlConnection 自动登记。但 EF Core 检查并加入环境事务。

IE EF 不依赖 ADO.NET DbConnection 来检测和登记环境事务。您可以使用嵌套的 TransactionScope 来抑制环境 Transaction:

using (var noTran = new TransactionScope(TransactionScopeOption.Suppress))

    using var db = new Db();
    //. . .
    noTran.Complete();

【讨论】:

【参考方案2】:

您需要scope.Complete(); 来提交事务。另外,我强烈建议使用 using 块和 TransactionScope 并让它负责处理而不是显式调用 Dispose

顺便说一句,Enlist 连接字符串关键字控制分布式事务的检测和登记,而不是本地事务。

【讨论】:

好的,我重新检查了文档,它确实声明设置 enlist false 只会选择退出分布式事务。除了使用“抑制”选项创建事务范围之外,有没有办法将 dbcontext 配置为不参与本地事务? 如果你不想在这里使用数据库事务,为什么要使用 TransactionScope? 在我的非示例代码中,我有一个需要成为事务的一部分的 dbcontext。它正在执行一些操作,并且在某些时候,它需要从数据库中获取大量数据。出于性能原因,我想使用多个数据库连接来获取这些数据。我通过跨多个线程(实际上是任务)创建 dbcontexts 来做到这一点。新生成的 dbcontexts 订阅了当前事务,使其成为分布式事务,不支持。

以上是关于为啥当 Enlist=False 时 Sqlserver 在事务中登记?的主要内容,如果未能解决你的问题,请参考以下文章

为啥当文件确实存在时`boost::filesystem::exists`返回false?

为啥当 == 为空值返回 true 时 >= 返回 false?

在 JavaScript 中,为啥 "0" 等于 false,但是当通过 'if' 测试时,它本身不是 false?

.Net Oracle TransactionScope的使用

为啥当 Debug 设置为 False 时,Django 会为静态媒体生成 HTTP 500 错误?

当 obj.hasOwnProperty('prop') 返回 false 时,为啥 obj.prop 返回 true? [复制]