简体   繁体   中英

SQLite and “Database is Locked”

Using SQLite, System.Data.SQLite and Dapper (in a Console Application; later Windows Service; high throughput); why "database is locked" is there anyway?

I even abstracted all calling to SQLite db in this method:

public static void LocalDbScope(Action<IDbConnection> action)
{
    try
    {
        lock (DbLock)
        {
            using (var connection = Open(LocalStorageConnectionString))
            {
                action(connection);
            }
        }
    }
    catch (Exception xux)
    {
        ErrLog.Error(xux);
        throw;
    }
}

Turning on the memory-mapped option did not help either:

connection.Execute("PRAGMA wal_autocheckpoint=32; PRAGMA journal_size_limit = 2048;");
connection.Execute("PRAGMA mmap_size=" + GB);

And this is connection string:

var builder = new SQLiteConnectionStringBuilder
{
    DataSource = storageDbFilePath,
    FailIfMissing = false,
    PageSize = 32 * KB,
    CacheSize = 10 * MB,
    ForeignKeys = false,
    UseUTF16Encoding = false,
    Pooling = true,
    JournalMode = SQLiteJournalModeEnum.Wal,
    SyncMode = SynchronizationModes.Normal,
    DateTimeKind = DateTimeKind.Utc,
    DateTimeFormat = SQLiteDateFormats.ISO8601,
    DefaultIsolationLevel = IsolationLevel.ReadCommitted,
    DefaultTimeout = (int)TimeSpan.FromMinutes(1).TotalMilliseconds
};
LocalStorageConnectionString = builder.ToString();

What am I missing here?

Note: When you google for "database is locked", all the top results (and whole first page) is about this problem in different programming languages and platforms. It seems there is something else about SQLite that I can not filter out of this picture.

As stated in my comment, I have NO idea what-so-ever, is going on without seeing more of your code.

Still, if you are not willing to change Dapper to Sqlite-net, below is a small non-blocking example, using your abstraction, which is not throwing any exceptions. Hope it helps you figure it out.

using System;
using System.Data;
using System.Data.SQLite;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Dapper;

namespace MyConsoleApplication
{
    public class Program
    {
        static void Main(string[] args)
        {
            var test = new TestSQLite();
            test.GoForIt();
        }
    }

    public class Entity
    {
        public int Id { get; set; }
        public string Content { get; set; }
    }

    public class TestSQLite
    {
        private const string ConnectionString = "Data Source=sqlitetest.sqlite";
        private static readonly object DbLock = new object();

        public void GoForIt()
        {
            CreateTable();

            var random = new Random();

            for (int i = 0; i < 100; i++)
            {
                if ( i % 2 != 0)
                {
                    Task.Factory.StartNew(() => Thread.Sleep(random.Next(0, 200))).ContinueWith(other => 
                        LocalDbScope(action =>
                            {
                                var entity = new Entity {Content = "hoax"};
                                entity.Id = action.Query<int>(
                                    @"insert into entity (content) values (@Content); select last_insert_rowid()",
                                    entity).First();
                                var ids = action.Query<int>(@"select id from entity").ToList();
                                Console.WriteLine("Inserted id:{0}, all ids:[{1}]", entity.Id, string.Join(",", ids));
                            }));
                }
                else
                {
                    Task.Factory.StartNew(() => Thread.Sleep(random.Next(200, 500))).ContinueWith(other => 
                        LocalDbScope(action =>
                            {
                                action.Execute(@"delete from entity");
                                Console.WriteLine("Deleted all entities");
                            }));
                }
            }

            Console.ReadLine();
        }

        public static void LocalDbScope(Action<IDbConnection> action)
        {
            lock (DbLock)
            {
                using (var connection = new SQLiteConnection(ConnectionString))
                    action(connection);
            }
        }

        private static void CreateTable()
        {
            using (IDbConnection c = new SQLiteConnection(ConnectionString))
            {
                c.Execute(@"drop table if exists entity");
                c.Execute(@"create table entity (id integer primary key autoincrement, content varchar(100))");
            }
        }
    }
}

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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