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

标签 c# database sqlite locking system.data.sqlite

正如我从 SQLite FAQ 中读到的那样支持多进程读(SELECT),单进程写(INSERT,UPDATE,DELETE)数据库:

SQLite uses reader/writer locks to control access to the database. When any process wants to write, it must lock the entire database file for the duration of its update. But that normally only takes a few milliseconds. Other processes just wait on the writer to finish then continue about their business

我正在使用 System.Data.SQLite通过 C# 的适配器。

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

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

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

抱歉,我没有找到关于此机制的信息:)

谢谢。

更新:

我发现帖子说 exception will be raised带有特定的错误代码

这个说法对吗?

最佳答案

我自己调查过:

我创建了一个示例 SQLite 数据库 c:\123.db,其中一个表 Categories 包含两个字段:ID (uniqueidentifier) 和 名称 (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 - 您可以使用特殊的枚举 ReturnCode 字段代替。所有代码描述here .

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

关于c# - 通过 System.Data.SQLite 和 c# 对单个 SQLite 数据库文件进行多次访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15383615/

相关文章:

c# - 我怎样才能从队列中创建一个 IObservable,这样序列就不会在队列为空时结束?

c# - 从文本文件中读取值

ruby-on-rails - 测试时切换分支导致数据库不存在错误

ruby-on-rails - 即使有要返回的记录,Rails find 也会返回 nil

iOS sqlite3 - 如果文件在 sqlite3_open 之后发生变化怎么办

c# - 使用 C# 访问、阅读和删除我的网络邮件中的邮件的应用程序

c# - Visual Studio 错误?

sql-server - 如何撤消 sp_addlinkedserver abc ,'SQL Server' ?

导出后Mysql数据库表为空

sqlite - SQLite中的.journal文件