通过System.Data.SQLite和c#对单个SQLite数据库文件进行多重访问

本文关键字:SQLite 文件 数据库 访问 单个 Data System 通过 | 更新日期: 2023-09-27 18:03:36

我可以从SQLite FAQ中读取它支持多进程读取(SELECT)和只有一个进程写入(INSERT, UPDATE, DELETE)数据库在任何时刻:

SQLite使用读写锁来控制对数据库的访问。当任何进程想要写入时,它必须锁定整个数据库文件在其更新期间。但这通常只需要几个毫秒。其他进程只是等待写程序完成继续他们的业务

我使用System.Data。SQLite适配器通过c#.

是否有人可以解释一下,究竟这个过程是如何进行的?

这个过程是否自动工作,如果有另一个写SQLiteCommand已经在同一数据库上执行,那么写SQLiteCommand将简单地等待?

或者可能会抛出一个异常?什么样的?

对不起,但是我没有找到关于这个机制的信息:)

谢谢。

更新:

我发现一个帖子说异常将被引发带有一个特定的错误码

这个说法正确吗?

通过System.Data.SQLite和c#对单个SQLite数据库文件进行多重访问

我已经亲自调查过了:

我创建了一个示例SQLite数据库c:'123.db,其中一个表Categories包含两个字段:ID(惟一标识符)和Name (nvarchar)。

然后我写了一些多线程代码来模拟对数据库的多次写访问(如果使用此代码,请不要忘记为您的项目添加System.Data.SQLite引用):

using System;
using System.Data.SQLite;
using System.Threading.Tasks;
namespace SQLiteTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var tasks = new Task[100];
            for (int i = 0; i < 100; i++)
            {
                tasks[i] = new Task(new Program().WriteToDB);
                tasks[i].Start();
            }
            foreach (var task in tasks)
                task.Wait();
        }
        public void WriteToDB()
        {
            try
            {
                using (SQLiteConnection myconnection = new SQLiteConnection(@"Data Source=c:'123.db"))
                {
                    myconnection.Open();
                    using (SQLiteTransaction mytransaction = myconnection.BeginTransaction())
                    {
                        using (SQLiteCommand mycommand = new SQLiteCommand(myconnection))
                        {
                            Guid id = Guid.NewGuid();
                            mycommand.CommandText = "INSERT INTO Categories(ID, Name) VALUES ('" + id.ToString() + "', '111')";
                            mycommand.ExecuteNonQuery();
                            mycommand.CommandText = "UPDATE Categories SET Name='222' WHERE ID='" + id.ToString() + "'";
                            mycommand.ExecuteNonQuery();
                            mycommand.CommandText = "DELETE FROM Categories WHERE ID='" + id.ToString() + "'";
                            mycommand.ExecuteNonQuery();
                        }
                        mytransaction.Commit();
                    }
                }
            }
            catch (SQLiteException ex)
            {
                if (ex.ReturnCode == SQLiteErrorCode.Busy)
                    Console.WriteLine("Database is locked by another process!");
            }
        }
    }
}

在我的Core2Duo E7500的结果是,异常永远不会引发!

看起来SQLite已经优化到足以满足我的需求(锁/解锁真的很快,通常只需要几毫秒,正如SQLite FAQ告诉我们的那样)-太棒了!

请注意,不需要为SQLiteException检索整数ErrorCode -您可以使用特殊的enum ReturnCode字段来代替。所有代码都在这里描述。