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

EF Core事务中Raw SQL的内存占用及相关技术疑问

EF Core事务批量操作的内存与行为疑问解答

先看你提供的代码:

using var reader = new MyReader(myStream);
using var context = new BloggingContext();
using var transaction = context.Database.BeginTransaction();

try
{
    while (!reader.EndOfStream()) 
    {
        var myObj = reader.ReadNextObject();
        context.Database.ExecuteSqlRaw("INSERT INTO [MyTable] ([Col1], [Col2]) VALUES ({0}, {1})", 
                                       myObj.prop1, myObj.prop2);
    }

    transaction.Commit();
}
catch (Exception)
{
    // Exception handling
}

针对你的三个疑问,解答如下:

1. myObj变量引用的对象能否在事务提交前被垃圾回收,还是会被全部加载到内存中?

可以被垃圾回收。每次循环里的myObj是局部变量,当循环进入下一次迭代时,上一个myObj已经没有任何活跃引用指向它——ExecuteSqlRaw执行完成后不会保留对它的引用,也不会把它存入EF Core的上下文缓存(因为你用的是直接执行SQL的方式,不是通过Add实体再SaveChanges)。所以GC会在合适时机回收这些对象,不会把数百万个myObj堆积在内存里。

2. 执行的所有SQL命令是在内存中存储直到事务提交,还是会立即发送到数据库?

会立即发送到数据库执行。ExecuteSqlRaw是同步执行方法,每次调用都会生成对应的INSERT语句并发送给数据库执行,只是这些操作都处于同一个事务边界内。数据库会把这些变更暂存在事务日志里,直到你调用Commit才会将变更持久化到磁盘;如果中途回滚,所有变更都会被丢弃。客户端内存不会堆积这些SQL命令。

3. 该操作会锁定[MyTable]直到事务提交吗?

这个说法不准确,要看数据库的隔离级别和锁机制(以SQL Server为例,默认是READ COMMITTED隔离级别):

  • 默认情况下,INSERT操作只会锁定当前插入的行,不会直接锁整个表。
  • 但如果批量插入的行数极多,或者数据库存在其他并发操作,可能会触发锁升级(比如从行锁升级为页锁,极端情况可能升级为表锁),这时候才会出现表级锁。但这不是必然发生的,不能默认认为整个表会被锁到事务提交。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 02:30:48