SQLite错误:数据库已锁定

时间:2014-07-27 14:44:00

标签: multithreading qt sqlite database-locking

我是Qt开发的新手,它处理线程(信号和插槽)和数据库(以及SQLite)的方式。我已经开始研究上述技术已有4周了。这是我第一次在SO上发帖提问,我觉得在你找到所有人之前我已经做过研究。这可能看起来有点长,可能是重复的,但是我要求你们一次彻底阅读它,然后将它作为副本或tl解决;博士。

上下文

我正在开发一个在数据库上执行特定操作X的Windows应用程序。该应用程序是在Qt中开发的,并使用QSQLite作为数据库引擎。它是单线程应用程序,即表格是按顺序处理的。但是,随着DB大小的增加(表和记录的数量),此处理变得更慢。此操作X的结果写在同一DB中的单独结果表中。正在进行的处理对于这个问题并不重要,但从基本的角度来看,它的作用是什么:

从Table_X_1中读取一行
从Table_X_2中读取一行
对行进行一些操作(仅读取)
将结果推送到Table_X_Results表中(这是在DB上执行的唯一写操作)

Table_X_1和Table_X_2的列数和行数以及行数相同,只是数据可能不同。

我想做的事

为了提高性能,我试图让应用程序多线程化。最初我正在产生两个线程(使用QtConcurrentRun)。这两个表可以分为两种类型,比如A和B.每个线程将处理两种类型的表。线程内的处理保持相同,即,在每个线程内,表顺序处理。

该函数使用SELECT来获取要处理的行,并使用INSERT将结果插入到结果表中。为了插入结果,我正在使用交易。

在开始实际操作之前,我正在创建所有中间表,结果表和索引。我每次都打开和关闭连接。对于线程,我在进入循环之前创建并打开一个连接(每个线程一个)。

问题

在我的处理功能中,我得到了以下(讨厌的,臭名昭着的,顽固的)错误:

QSqlError(5,"无法获取行","数据库被锁定")

当我尝试从DB读取一行时(使用SELECT),我收到此错误。这与我在结果表中执行INSERT的功能相同。 SELECT和INSERT位于同一事务中(开始和提交对)。对于INSERT我使用预准备语句(SQLiteStatement)。

我正在做的看似奇怪的事情的原因

  1. 我正在使用QtConcurrentRun来创建线程,因为它很简单!我尝试过使用QThread(不是继承QThread,而是使用other方法)。这也会导致同样的问题。
  2. 我正在使用DSQLITE_THREADSAFE = 0进行编译,以避免应用程序崩溃。如果我使用默认值(DSQLITE_THREADSAFE = 1),我的应用程序在SQLiteStatement :: recordSet-> Reset()时崩溃。此外,使用默认选项,内部SQLITE同步机制开始起作用,这可能不可靠。如果需要,我将采用显式同步。
  3. 使应用程序具有多线程以提高性能,而不是this。我正在处理那里推荐的所有优化工作。
  4. 在QSQLITE_BUSY_TIMEOUT = 0时使用QSqlDatabase :: setConnectOptions。一个链接表明它会阻止DB立即被锁定,因此可能会给我的线程足够的时间和平地死掉#34;。这失败了:数据库比以前更频繁地被锁定。
  5. 观察

    1. 只有当其中一个线程返回时,数据库才会进入锁定状态。这种行为是一致的。
    2. 使用DSQLITE_THREADSAFE = 1进行编译时,应用程序会在其中一个线程返回时崩溃。在我的函数中的SQLiteStatement :: recordSet-> Reset()和sqlite3.c中的winMutexEnter()(从EnterCriticalSection()调用)调用堆栈点。这也是一致的。
    3. 使用QtConcurrentRun创建的线程不会立即死亡。
    4. 如果我使用QThreads,我无法让他们返回。也就是说,即使我已正确连接信号和插槽,我觉得线程永远不会返回。等待线程的正确方法是什么?它们需要多长时间才能死掉?
    5. 完成执行的线程永远不会返回,它已锁定数据库,从而导致错误。
    6. 我检查了SQLITE_BUSY,并尝试让线程睡眠,但无法使其工作。在Qt中睡眠的正确方法是什么(对于使用QtConcurrentRun或QThreads创建的线程)?
    7. 当我关闭我的连接时,我收到此警告:

      QSqlDatabasePrivate :: removeDatabase:connection' DB_CONN_CREATE_RESULTS'仍在使用中,所有查询都将停止工作。

      这有什么意义吗?某些链接表明由于使用本地QSqlDatabase而出现此警告,并且如果连接成为类成员,则不会出现此警告。但是,这可能是我遇到问题的原因吗?

    8. 进一步的实验

      1. 我正在考虑创建另一个只包含结果表的数据库(Table_X_Results)。理由是,虽然线程将从一个DB(我当前拥有的DB​​)读取,但它们将写入另一个DB。但是,我可能仍然面临同样的问题。此外,我在论坛和wiki上读到, IS 可能有两个线程在同一个DB上进行读写操作。那么为什么我不能让这个场景起作用呢?
      2. 我目前正在使用SQLITE版本3.6.17。这可能是问题吗?如果我使用3.8.5版本会更好吗?
      3. 我试图发布我已经探索过的网络资源,但是我收到一条消息说“#34;我需要10个代表来发布2个以上的链接"。任何帮助/建议将不胜感激。

0 个答案:

没有答案