出于某种原因,一旦我在两个不同的上下文中对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支持来自单独的数据库连接的多个同时读取事务,可能是在单独的线程或进程中,但仅同时写入交易。
我猜这是给您带来问题的原因。 正如评论中所述,使用SQLITE作为RDBMS的“测试”实体具有某些限制,测试仪需要在测试中充分了解并考虑。 在哪里不能模拟实际使用的RDBM的行为,建议使用SAME
SAMESAMERDBMS,如生产中(当然是测试实例)。 如今,有许多工具可以支持这一点,例如使用容器化。