欢迎光临
个人技术文档整理

EF Core 三类事务(SaveChanges、DbContextTransaction、TransactionScope)

默认事务(SaveChanges)

  • SaveChanges :一次性将本地缓存中所有的状态变化,一次性提交到数据库,这就是一个事务,要么统一成功,要么统一回滚
  • 使用场景:一个DBContext,即一个数据库的EF的上下文,不能控制多个数据库。
  • 关闭默认事务:db_a.Database.AutoTransactionsEnabled = false ; //这个新版本不生效了
            /// <summary> 
            /// SaveChanges :一次性将本地缓存中所有的状态变化一次性提交到数据库,这就是一个事务,要么统一成功,要么统一回滚
            /// 使用场景:一个DBContext,即一个数据库的EF的上下文,不能控制多个数据库。
            /// </summary> 
            private string DoTrans_SaveChanges()
            {
                try
                {
                    using (A_DbContext db_a = new A_DbContext())
                    {
                        //关闭SaveChanges的默认事务--这个新版本不生效了
                        db_a.Database.AutoTransactionsEnabled = false;
    
                        var gid = Guid.NewGuid().ToString("N");
    
                        //插入一条正确的
                        db_a.Add(new UserInfo()
                        {
                            Name = "张三_A",
                            G_Id = gid,//唯一键
                            Money = 100,
                        });
    
                        //插入一条错误的 (唯一键报错)
                        db_a.Add(new UserInfo()
                        {
                            Name = "张三_B",
                            G_Id = gid,//唯一键 Guid.NewGuid().ToString("N"),//
                            Money = 99,
                        }); ;
    
                        var row = db_a.SaveChanges();
                        return "保存成功,影响行数=" + row;
                    }
                }
                catch (Exception ex)
                {
                    return "出错了两条数据都没有执行成功:" + ex.Message;
                }
            }

 

DbContextTransaction

  • 通常用于手动接管事务,某些操作是一个事务,某些操作是另外一个事务。
  •  使用场景:EF调用SQL语句的时候使用该事务、 多个SaveChanges;不同控制多个数据库
  •  使用方式:BeginTransaction开启事务、Commit提交事务、Rollback回滚事务、Dispose销毁,如果用Using包裹的话,不再需要手动Rollback,走完Using会自动回滚。如果不用Using包裹事务,就需要在Catch中手动RollBack回滚,并且最好最后手动的Dispose一下
    private string DoTrans_DbContextTransaction()
            {
    
                using A_DbContext db = new();
                var transaction = db.Database.BeginTransaction();
                try
                {
                    var userEntity = new UserInfo()
                    {
                        Name = "张三_B",
                        G_Id = Guid.NewGuid().ToString("N"),
                        Money = 99,
                    };
                    db.Add(userEntity);
                    var row_1 = db.SaveChanges();
    
                    db.Add(new Product() { Name = "产品_1", UserInfo_Id = userEntity.Id });
                    var row_2 = db.SaveChanges();
    
                    transaction.Commit();
                    return $"保存成功,UserInfo={row_1},Product={row_2}";
                }
                catch (Exception ex)
                {
                    transaction.Rollback();
                    return "出错了:" + ex.ToString();
                }
                finally
                {
                    transaction.Dispose();
                }
            }

     

        

TransactionScope-环境事务

  •  使用场景 
     1、同一个上下文的事务。(多个SaveChanges(自增主键后续用到的情况)、SaveChanges和EF调用SQL语句混用)
     2、多种数据库技术,访问同一个数据库的事务
     3、同一个数据库,多个不同的上下文是支持的
    4、不同数据库的上下文是不支持的,目前Core平台下不支持分布式事务
  •  使用方式
    new TransactionScope创建事务、Complete提交事务、 Transaction.Current.Rollback();回滚事务、Dispose销毁对象。如果用Using包裹的话,不再需要手动Rollback,走完Using会自动回滚。如果不用Using包裹事务,就需要在Catch中手动RollBack回滚,并且最好最后手动的Dispose一下。
     private string DoTrans_TransactionScope()
            {
                using (var scope = new TransactionScope())
                {
                    try
                    {
                        //A数据库
                        using A_DbContext db_a = new();
                        var userEntity = new UserInfo()
                        {
                            Name = "张三_A",
                            G_Id = Guid.NewGuid().ToString("N"),
                            Money = 99,
                        };
                        db_a.Add(userEntity);
                        var row_1 = db_a.SaveChanges();
    
    
                        //A数据库
                        using A2_DbContext db_a2 = new();
                        db_a2.Add(new Product() { Name = "产品_1", UserInfo_Id = userEntity.Id });
                        var row_2 = db_a2.SaveChanges();
    
    
                        //综合提交
                        scope.Complete();
    
                        return $"保存成功,UserInfo={row_1},Product={row_2}";
                    }
                    catch (Exception ex)
                    {
                        return "出错了:" + ex.ToString();
                    }
                }
            }

     

System.Transactions 的限制,不同数据库的上下文是不支持的,目前Core平台下不支持分布式事务

  1. 开启msdtc服务的步骤: cmd命令→ net start msdtc ,然后发现报错:This platform does not support distributed transactions.说明目前Core平台下不支持分布式事务
  2. EF Core 依赖数据库提供程序以实现对 System.Transactions 的支持。 如果提供程序未实现对 System.Transactions 的支持,则可能会完全忽略对这些 API 的调用。 SqlClient 支持它。

  3. 自 .NET Core 2.1 起,System.Transactions 的 .NET Core 实现当前不包括对分布式事务的支持,因此不能使用 TransactionScope 或 CommittableTransaction 来跨多个资源管理器协调事务。

  4. 参考资料:https://learn.microsoft.com/zh-cn/ef/core/saving/transactions

            /// <summary>
            /// 不支持 的分布式事务
            /// </summary>
            /// <returns></returns>
            private string DoTrans_TransactionScope_NoSupport()
            {
                using (var scope = new TransactionScope())
                {
                    try
                    {
                        //A数据库
                        using A_DbContext db_a = new();
                        var userEntity = new UserInfo()
                        {
                            Name = "张三_A",
                            G_Id = Guid.NewGuid().ToString("N"),
                            Money = 99,
                        };
                        db_a.Add(userEntity);
                        var row_1 = db_a.SaveChanges();
    
    
                        //B数据库
                        using B_DbContext db_b = new();
                        db_b.Add(new Product() { Name = "产品_B", UserInfo_Id = userEntity.Id });
                        var row_2 = db_b.SaveChanges();
    
    
                        //综合提交
                        scope.Complete();
    
                        return $"保存成功,UserInfo={row_1},Product={row_2}";
                    }
                    catch (Exception ex)
                    {
                        return "出错了:" + ex.ToString();
                    }
                }
            }

     

 

赞(5)