SQLite只支持一个事务吗?

3

在使用ADO.NET时(也许我说错了,不知道它叫什么),我注意到我只能通过连接开始一个事务,而命令似乎有command.Transaction,可以获取事务数据,但本身并不开始事务?实际上,在查看System.Data.SQLite时,我发现了这个问题。

// Summary:
    //     The transaction associated with this command. SQLite only supports one transaction
    //     per connection, so this property forwards to the command's underlying connection.
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public SQLiteTransaction Transaction { get; set; }

那么SQLite只支持一个事务周期吗?我尝试打开另一个连接,但是我的事务抛出了一个关于数据库被锁定的异常。所以我不能有多个并发连接吗?

3个回答

4

每个连接只能有一次事务,但可以有多个连接(每个连接都有自己的活动事务)。

更新:有趣。我不知道共享缓存模式。如果您的连接正在使用该模式,则所有使用相同共享缓存的连接仅可用一个事务。请参阅SQLite shared-cache mode


这并非完全正确。共享缓存模式不会影响事务数量。当关闭共享缓存时,每个数据库连接必须独占地锁定数据库文件才能写入它。因此,所有连接只有一个可用的写事务。然而,在共享缓存模式下,对于进程中的所有线程,锁定是基于每个表进行的。在任一模式下,可以并行进行读取。 - jowo

1

在一个事务中,直到事务完成之前,您只能读/写1个连接。因此,如果您执行跨多个SQL语句的业务交易,则必须传递连接对象,如下所示:

public class TimeTableService
    {
        ITimeTableDataProvider _provider = new TimeTableDataProvider();

        public void CreateLessonPlanner(WizardData wizardData)
        {
            using (var con = _provider.GetConnection())
            using (var trans = new TransactionScope())
            {
                con.Open();

                var weekListA = new List<Week>();
                var weekListB = new List<Week>();

                LessonPlannerCreator.CreateLessonPlanner(weekListA, weekListB, wizardData);

                _provider.DeleteLessonPlanner(wizardData.StartDate, con);

                _provider.CreateLessonPlanner(weekListA, con);
                _provider.CreateLessonPlanner(weekListB, con);

                _provider.DeleteTimeTable(TimeTable.WeekType.A, con);
                _provider.StoreTimeTable(wizardData.LessonsWeekA.ToList<TimeTable>(), TimeTable.WeekType.A, con);

                _provider.DeleteTimeTable(TimeTable.WeekType.B, con);
                _provider.StoreTimeTable(wizardData.LessonsWeekB.ToList<TimeTable>(), TimeTable.WeekType.B, con);

                trans.Complete();
            }
        }
    }

使用语句会自动释放/关闭连接和事务资源。

然后在每个数据提供程序方法中执行操作。

using(var cmd = new SQLiteCommand("MyStatement",con)
{
   // Create params + ExecuteNonQuery
}

TransactionScope类是.NET 3.5中的新功能,如果发生异常,它会自动执行回滚操作。易于处理...


1

我不确定关于多个连接的问题,这可能与连接锁定文件有关,因为SQLite是基于文件而不是基于服务器的数据库(在基于服务器的数据库上,服务器会锁定所有文件并处理并发连接)。

您一次只能打开一个事务。这应该很直观,因为在开始事务后发生的所有事情都在该事务中,直到rollbackcommit。然后您可以开始新的事务。 SQLite要求所有命令都在事务中,因此如果您没有手动打开新事务,它将为您执行此操作。

如果您担心嵌套事务,可以使用savepoint来模拟它们。文档


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接