大数跨境
0
0

EF Core 数据保存与事务管理原理解析

EF Core 数据保存与事务管理原理解析 阿笨AI.NET
2025-05-18
2

一、EF Core 保存数据原理(SaveChanges()

 简单理解:

DbContext.SaveChanges() 的核心作用是:
将 DbContext 中“已跟踪”的实体对象的状态变化(如新增、修改、删除)转换为对应的 SQL 语句,并提交给数据库执行。

🧠 背后的执行流程:

  1. 变更追踪(Change Tracking)

    DbContext 会追踪你对实体对象做的操作(例如 Add()Update()Remove()),并记录实体的状态(AddedModifiedDeleted 等)。
  2. 生成命令(Command Generation)

    调用 SaveChanges() 时,EF Core 会根据变更状态,构造 SQL 命令(如 INSERTUPDATEDELETE)。
  3. 执行命令

    EF Core 会按顺序执行这些命令,最终把更改持久化到数据库中。

二、事务操作原理

 什么是事务?

事务是一组操作的集合,这组操作要么全部成功,要么全部失败。EF Core 默认就使用了事务来保护数据一致性。

🧠 EF Core 中事务的方式有两种:

 自动事务(SaveChanges 内部自带)

context.SaveChanges();
  • EF Core 默认在 SaveChanges() 内部自动创建一个事务(仅在多条命令时)。
  • 如果所有命令都执行成功,就提交;否则就回滚。

 手动控制事务

适用于:多个 DbContext.SaveChanges()、跨多个表操作、或需精细控制时。

using var transaction = context.Database.BeginTransaction();

try
{
    context.Add(...);
    context.SaveChanges();

    context.Update(...);
    context.SaveChanges();

    transaction.Commit();
}
catch
{
    transaction.Rollback();
}

三、原理整合:保存数据 + 事务完整图解

步骤

EF Core 做了什么

1

DbContext 跟踪实体的状态(Add/Update/Delete)

2

调用 SaveChanges()

 时,构建 SQL 命令

3

EF Core 打开数据库连接

4

自动或手动开启事务

5

顺序执行 SQL 命令,若任一失败则回滚

6

成功则提交事务

7

关闭连接


六、理解 SaveChanges() 默认会在多个命令之间启用事务


理解 SaveChanges() 默认会在多个命令之间启用事务的意思是,当你通过 DbContext 保存数据时,如果执行多个操作(例如插入、更新、删除多个实体),EF Core 会将这些操作放在同一个事务中进行处理。这意味着,如果这些操作中的任何一个失败了,所有操作都会回滚,确保数据库的数据一致性

1. 为什么需要事务?

事务的作用是保证一组数据库操作要么全部成功,要么全部失败。在处理多个数据库命令时,如果不使用事务,一个命令成功后,另一个失败了,数据库就会处于不一致的状态。例如:

  • 执行插入新用户记录成功,但插入日志记录失败,导致数据库只有用户数据而没有日志数据,数据不完整。

2. SaveChanges 中的事务机制

SaveChanges() 方法会自动在多个数据库操作之间启用一个隐式的事务。EF Core 会在调用 SaveChanges() 时自动开启一个事务,并在所有命令成功执行后提交该事务。如果其中任何一个命令执行失败,整个事务会被回滚。


3. 举例:多个命令和自动事务

假设你有两个实体:User 和 UserLog,我们希望在新增一个用户时,也同时插入一条操作日志。如果这些操作之间没有事务控制,可能会导致部分操作成功,部分操作失败,从而造成数据的不一致。

示例代码:


public class MyDbContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<UserLog> UserLogs { get; set; }
}

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class UserLog
{
    public int Id { get; set; }
    public int UserId { get; set; }
    public string Action { get; set; }
}

public void AddUserAndLog()
{
    using (var context = new MyDbContext())
    {
        var user = new User { Name = "张三" };
        context.Users.Add(user);  // 第1个操作:添加用户

        var log = new UserLog { UserId = user.Id, Action = "用户注册" };
        context.UserLogs.Add(log);  // 第2个操作:添加日志

        context.SaveChanges();  // 第3个操作:保存到数据库,自动在多个操作之间启用事务
    }
}

执行流程:

  1. context.Users.Add(user)
     会将 user 实体的状态设置为 Added,表示插入操作。
  2. context.UserLogs.Add(log)
     会将 log 实体的状态设置为 Added,表示插入操作。
  3. 调用 SaveChanges() 时,EF Core 会:
    • 自动开启事务
      ,将这两个操作放在一个事务中。
    • 生成 SQL 命令:一个是 INSERT INTO Users,另一个是 INSERT INTO UserLogs
    • 将这些命令按顺序执行,确保两者都成功执行,否则事务会回滚。

事务成功

如果两个操作都成功,EF Core 会提交事务,数据会持久化到数据库中,Users 表和 UserLogs 表都会有对应的记录。

事务回滚(失败情况)

如果其中某一个操作失败(例如插入日志记录时发生错误),事务会被回滚,数据库中的任何变化都会被撤销。也就是说,Users 表中的数据也不会被保存。


4. 具体示例:失败回滚

假设在插入 User 成功后,插入 UserLog 时发生了一个错误(例如违反了数据库约束)。EF Core 会自动回滚整个事务,即使 User 的插入是成功的,它也不会被保存到数据库。


public void AddUserAndLogWithError()
{
    using (var context = new MyDbContext())
    {
        var user = new User { Name = "李四" };
        context.Users.Add(user);  // 第1个操作:添加用户(成功)

        var log = new UserLog { UserId = user.Id, Action = "用户注册" };
        context.UserLogs.Add(log);  // 第2个操作:添加日志(故意制造错误)

        // 假设日志插入操作失败(例如外键约束失败)
        try
        {
            context.SaveChanges();  // 整个事务会回滚
        }
        catch (Exception ex)
        {
            Console.WriteLine("发生错误,事务已回滚:" + ex.Message);
        }
    }
}

结果:

  • User
     插入成功后,UserLog 插入失败。
  • 由于事务回滚,User 的插入操作也会被撤销。

总结:

  • 默认情况下,SaveChanges() 会在你执行多个操作时,自动在这些操作之间启动一个事务,确保数据库的操作要么全部成功,要么全部失败。
  • 这种事务控制机制避免了数据的不一致,保证了多操作的原子性。

【声明】内容源于网络
0
0
阿笨AI.NET
✅ 专注 AI.NET编程领域,带你快速掌握核心技能!🔥
内容 289
粉丝 0
阿笨AI.NET ✅ 专注 AI.NET编程领域,带你快速掌握核心技能!🔥
总阅读195
粉丝0
内容289