简体   繁体   English

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

[英]Multiple access to a single SQLite database file via System.Data.SQLite and c#

As I can read from SQLite FAQ it supports multiple processes reading (SELECT) and only one process writing (INSERT, UPDATE, DELETE) database at any moment in time: 正如我可以从SQLite FAQ中读到的,它支持多个进程读取(SELECT),并且在任何时刻都只支持一个进程写入(INSERT,UPDATE,DELETE)数据库:

SQLite uses reader/writer locks to control access to the database. SQLite使用读取器/写入器锁来控制对数据库的访问。 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 其他流程只是等待作者完成然后继续他们的业务

I'm using System.Data.SQLite adapter via c#. 我通过c#使用System.Data.SQLite适配器。

Could someone expalin me plz, how exactly this process is going on? 有人可以告诉我PLZ,这个过程到底是怎么回事?

Will this process work automatically and writing SQLiteCommand will simply wait if there is another writing SQLiteCommand already executing over the same database? 这个过程是否会自动运行,编写SQLiteCommand只会等待另一个SQLiteCommand已经在同一个数据库上执行?

Or maybe it will throw an exception? 或者它可能会抛出异常? What kind of it? 什么样的?

Sorry but I found no information about this mechanics :) 抱歉,但我没有找到有关此机制的信息:)

Thank you. 谢谢。

UPDATE: 更新:

I've found post saying that exception will be raised with a specific errorcode 我发现帖子说异常会引发一个特定的错误代码

Is that statement correct? 这句话是否正确?

I've investigated it by myself: 我自己调查了一下:

I created a sample SQLite database c:\\123.db with one table Categories containing two fields: ID (uniqueidentifier) and Name (nvarchar). 我创建了一个示例SQLite数据库c:\\123.db ,其中包含一个表包含两个字段的CategoriesID (uniqueidentifier)和Name (nvarchar)。

I then wrote some multi-thread code to emulate multiple write access to the database (don't forget to add a System.Data.SQLite reference to your project if you use this code): 然后我编写了一些多线程代码来模拟对数据库的多次写访问(如果使用此代码,请不要忘记向项目添加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!");
            }
        }
    }
}

The result on my Core2Duo E7500 is that Exception is never raised! 我的Core2Duo E7500的结果是永远不会出现异常!

Looks like SQLite is optimised enough for my needs (locking/unlocking is really fast and normally only takes a few milliseconds as SQLite FAQ tells us) - Great! 看起来SQLite已根据我的需求进行了优化(锁定/解锁非常快,通常只需几毫秒,如SQLite FAQ告诉我们的那样) - 太棒了!

Note that there is no need to retrieve an integer ErrorCode for an SQLiteException - you can use a special enum ReturnCode field instead. 请注意,不需要为SQLiteException检索整数ErrorCode - 您可以使用特殊的枚举ReturnCode字段。 All codes are described here . 这里描述所有代码。

Hope this information will help somebody. 希望这些信息对某人有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM