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

C# 通过System.Data.SQLite和c对单个SQLite数据库文件进行多重访问,c#,database,sqlite,locking,system.data.sqlite,C#,Database,Sqlite,Locking,System.data.sqlite,如我所知,它支持多个进程读取、选择和仅一个进程写入随时插入、更新、删除数据库: SQLite使用读写器锁来控制对数据库的访问。 当任何进程想要写入时,它必须锁定整个数据库文件 在其更新期间。但这通常只需要几分钟 毫秒。其他进程只需等待编写器完成即可 继续他们的生意 我通过c使用适配器 有人能告诉我这个过程到底是怎么进行的吗 如果在同一数据库上已经有另一个正在写入SQLiteCommand的命令正在执行,那么这个过程是否会自动工作,写入SQLiteCommand将只是等待 或者它会抛出一个异常?什

如我所知,它支持多个进程读取、选择和仅一个进程写入随时插入、更新、删除数据库:

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

我通过c使用适配器

有人能告诉我这个过程到底是怎么进行的吗

如果在同一数据库上已经有另一个正在写入SQLiteCommand的命令正在执行,那么这个过程是否会自动工作,写入SQLiteCommand将只是等待

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

抱歉,我找不到有关此机制的信息:

多谢各位

更新:

我发现有一个帖子说,有一个特定的错误代码


那句话对吗

我自己调查过:

我创建了一个示例SQLite数据库c:\123.db,其中一个表类别包含两个字段:ID uniqueidentifier和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已经针对我的需要进行了充分的优化,锁定/解锁速度非常快,通常只需要几毫秒,这告诉我们-太棒了

请注意,无需检索SQLiteException的整数ErrorCode-您可以改用特殊的enum ReturnCode字段。描述了所有代码


希望这些信息能对某人有所帮助。

还没有:我更喜欢在编码之前阅读教程-以获得优化和正确的解决方案…如果您更喜欢优化和正确的解决方案,请不要将SQLite用于它未优化的内容;这是一个伟大的数据库,但它不是一个伟大的多用户数据库。我需要免费和轻量级的,我的意思是零配置和无服务器数据库为我的项目。因此,大多数多用户优化的数据库不适合我:您的代码证明,单个进程中的多个线程可以无缝地访问SQLite数据库。您是否能够测试多个不同的进程是否可以访问同一个数据库?首先,我想到的是在Test1.exe中编译该代码,然后在Main的第一行添加Process.StartTest1.exe并将其重新编译到Test2.exe。似乎是工作,但我从来没有测试过它…好主意!我刚刚使用这种方法进行了测试,它是有效的。多进程访问在SQLite上运行得很好。只是想补充一下。我正在编写一个基于NLog/SignalR的保证交付日志服务,该服务使用System.Data.SQLite写入本地数据库,以便后台线程将数据发送到LogStash,我有40个线程将日志消息发送到本地SignalR hub。它肯定是抛出了SQLite错误5:当单个进程处理来自其他进程的其他线程的消息时,数据库被锁定异常。@JamesEby SQLite使用内部日志记录,因此当某个操作由于块状态或其他原因而失败时,它会重试直到完成。所以,这不是内部条件,当然,您的插入没有丢失。事实上,如果您看到该消息,则会发生错误,稍后会重试。使用线程插入时,这种锁定错误很常见。除此之外,如果您有大量的线程读取,则使用WAL日志模型,因此写入和读取在单独的线程中,因此来自线程的写入不会影响可能的数千次并发读取。