You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core事务回滚失效:数据仍被提交至MySQL数据库

问题描述

原事务代码如下,当//业务逻辑部分出错时,明明执行了transaction.Rollback(),但数据仍被提交到MySQL数据库:

using (var transaction = _context.Database.BeginTransaction())
{
    try
    {
        // 业务逻辑(包含Remove、Add、Update、SaveChanges操作)
        _context.SaveChanges();
        transaction.Commit();
     } 
     catch 
     { 
         transaction.Rollback(); 
     }
}

后续补充代码发现,问题出在外部的SaveChanges提交了已回滚的变更:

public void AddUser() {
using (var transaction = _context.Database.BeginTransaction())
{
    try
    {
        // 业务逻辑
        _context.SaveChanges();
        transaction.Commit();
     } 
     catch 
     { 
         transaction.Rollback(); 
         throw;
     }
}
}

public void Init(){
 try {
   AddUser();
 } catch(Exception e) {
   _context.Logs.Add(new Log(e.Message));
   _context.SaveChanges();  // <-------- 这里提交了AddUser()中已回滚的变更
 }
}

问题根源

EF Core的DbContext会持续追踪所有实体变更,哪怕事务回滚,这些变更记录依然保存在上下文的变更追踪器中。当外部调用_context.SaveChanges()时,上下文会把所有追踪到的变更(包括之前事务里的Add/Update/Remove操作)一并提交到数据库,导致已回滚的变更被意外保存。

解决办法

方案1:使用短生命周期DbContext

在AddUser方法内部创建独立的DbContext实例,避免复用外部上下文。事务回滚后,新上下文会被销毁,外部上下文不会追踪到这些变更:

public void AddUser() {
    using (var newContext = new YourDbContext())
    using (var transaction = newContext.Database.BeginTransaction())
    {
        try
        {
            // 业务逻辑,使用newContext操作实体
            newContext.SaveChanges();
            transaction.Commit();
         } 
         catch 
         { 
             transaction.Rollback(); 
             throw;
         }
    }
}

方案2:手动清除变更追踪

在事务回滚后,清空上下文变更追踪器里的所有记录:

public void AddUser() {
using (var transaction = _context.Database.BeginTransaction())
{
    try
    {
        // 业务逻辑
        _context.SaveChanges();
        transaction.Commit();
     } 
     catch 
     { 
         transaction.Rollback();
         // 清除所有被追踪的实体变更
         foreach (var entry in _context.ChangeTracker.Entries())
         {
             switch (entry.State)
             {
                 case EntityState.Added:
                     entry.State = EntityState.Detached;
                     break;
                 case EntityState.Modified:
                 case EntityState.Deleted:
                     entry.Reload();
                     break;
             }
         }
         throw;
     }
}
}

这样外部调用_context.SaveChanges()时,只会提交日志的新增操作,不会包含之前回滚的变更。

内容的提问来源于stack exchange,提问作者Emilly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 04:10:15