SQLITE内存数据库不喜欢两个阶段提交

问题描述 投票:0回答:1
对SQLite内存DB进行模拟DB依赖性代码(而实际的生产运行时可以在非常不同的环境(例如MSSQL,DB2,Oracle,Sybase,Sybase)中发生。 我正在尝试构建一个两阶段的过程(对于保存与其关联的数据库上下文时,可以保存的操作日志)。有时,协议的更改发生在ActionLog表所在的同一数据库上。这是出现麻烦的地方。

出于某种原因,一旦我在两个不同的上下文中对SQLite-Inmemory-DB进行了两项交易,并尝试保存上下文2在保存上下文1之后,就会在30秒后抛出一个例外:“ SQLITE错误6:'数据库表是锁定'

这是使用的连接字符串:

var connectionString = $"Data Source=file:{DatabaseAlias};mode=memory;cache=shared"; optionsBuilder.UseSqlite(connectionString);

这是我设置的测试:

var context1 = factory.CreateDbContext(); var context2 = factory.CreateDbContext(); context1.WithTransaction(() => { var keysFromContext1 = context1.Keys.ToList(); keysFromContext1.First().Name = "Changed First"; context2.WithTransaction(() => { var employeesFromContext2 = context2.Employees.ToList(); employeesFromContext2.First().Name = "Changed Second"; context1.SaveChanges(); context2.SaveChanges(); }); });
这是交易处理的代码:

public void WithTransaction(Action action) { WithTransaction(action, IsolationLevel.ReadUncommitted); } public void WithTransaction(Action action, IsolationLevel isolationLevel) { if (Database.CurrentTransaction != null) { action(); return; } Database.BeginTransaction(isolationLevel); try { action(); Database.CommitTransaction(); } catch { Database.RollbackTransaction(); throw; } }
您可以看到,这两个上下文更改了不同实体的数据,但仍然会出现碰撞。

I还必须将默认的隔离级更改为readuncommited(又称“ dirty read”),否则该块将在通过context2.employees.tolist()呼叫加载数据时发生。 SQLITE一次无法处理多个交易,即使在完全不同的实体上工作,也必须处理 /回滚交易以便随后开始处理交易吗?是否总是有效地防止在同一数据库上进行两阶段的中央锁?

	

文档的第2.1节

SAI:

sqlite支持来自单独的数据库连接的多个同时读取事务,可能是在单独的线程或进程中,但仅同时写入交易。
c# sqlite entity-framework transactions .net-8.0
1个回答
0
投票
(我强调)

我猜这是给您带来问题的原因。 正如评论中所述,使用SQLITE作为RDBMS的“测试”实体具有某些限制,测试仪需要在测试中充分了解并考虑。 在哪里不能模拟实际使用的RDBM的行为,建议使用SAME

SAME
SAME

RDBMS,如生产中(当然是测试实例)。 如今,有许多工具可以支持这一点,例如使用容器化。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.