11

我有一个 SQLite 数据库,我在进程 A 中保持打开并写入它。我希望能够在进程 B 中以只读方式使用它。

根据文件

  • 如果数据库未锁定,则可能无法读取(或写入)数据库 -不合适
  • 如果数据库是共享的,那么两个进程可以读取它但第一个不能写入 -不合适
  • 如果一个进程想要写它需要一个独占锁,这意味着没有其他进程可以写 -不合适

进程 A 将进行大量小写入,因此我认为在每个事务提交上制作副本不会是有效的。

我能看到的唯一方法是让读者等到数据库进入 UNLOCKED 状态,在读取期间获得一个 SHARED 锁,然后释放它。同时,进程 A 将要写入并将被阻塞,直到锁可用 - 如果它曾经可用(如果进程 B 崩溃怎么办?)。这意味着进程 A 和进程 B 将争夺锁 - B 想要 SHARED 而 A 想要 EXCLUSIVE,这会减慢速度甚至导致并发问题。

有什么方法可以实现我的同时写作和阅读的目标吗?

4

3 回答 3

19

使用WAL 模式。它支持并发读取器和一个写入器。

于 2012-08-24T23:32:25.447 回答
0

至于 Android,您可以使用 WAL 模式。API 11 (严重)支持它。更好的支持从 API 16 开始。使用此代码将您的数据库连接切换到 WAL 模式:

int flags = SQLiteDatabase.CREATE_IF_NECESSARY;
if(walModeEnabled) {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
       flags = flags | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING;
   }
}

SQLiteDatabase db = SQLiteDatabase.openDatabase(databasePath.getPath(), null, flags);

// backward compatibility hack to support WAL on pre-jelly-bean devices
if(walModeEnabled) {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB &&
           Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
       db.enableWriteAheadLogging();
   } else {
       Log.w(TAG, "WAL is not supported on API levels below 11.");
   }
}

有关 SQLiteOpenHelper 和更深入的解释 WAL 模式如何在后台工作,请参阅我的文章:

https://www.skoumal.net/en/parallel-read-and-write-in-sqlite/

于 2016-10-17T09:48:33.283 回答
-7

您的问题的简单答案是 - “不可能”

即使你成功了 - 意味着你得到了错误的结果。

我认为您应该了解数据库的基础知识-

为什么数据库比文件处理和其他数据存储方法更好。

简单的回答——

您不能同时执行 WW、WR、RW 操作。

(W-写,R-读)

但是,您可以同时执行无限 RR 操作。

想想网上银行系统或铁路预订系统。

其中使用了数据库的一个特殊功能,即事务。

它遵循酸。

即原子性、一致性、隔离性、持久性。

原子性 - 完整或不完整。

一致性 - 在每个事务系统将从一个一致状态转到另一个一致状态之后。

隔离 - 每个事务都将彼此隔离执行。

(意味着如果写查询首先出现,它将首先执行)没有办法同时进行写和读操作。即使有纳秒的差异系统也会检测到它。但是,如果您成功的话。db 简单地拒绝它或执行具有更高优先级的操作。

耐用性 - 系统必须及时耐用。

--也许它比一个简单的数据库非常广泛,但它可能会帮助你理解。--

2.

SQLite 数据库文件被组织为页面。每页的大小是 512 和 SQLITE_MAX_PAGE_SIZE 之间的 2 的幂。SQLITE_MAX_PAGE_SIZE 的默认值为 32768。

SQLITE_MAX_PAGE_COUNT 参数通常设置为 1073741823,是单个数据库文件中允许的最大页数。尝试插入会导致数据库文件变得大于此大小的新数据将返回 SQLITE_FULL。

所以我们有 32768 * 1073741823,即 35,184,372,056,064(35 万亿字节)!

您可以在源代码中修改 SQLITE_MAX_PAGE_COUNT 或 SQLITE_MAX_PAGE_SIZE,但这当然需要为您的应用程序自定义构建 SQLite。据我所知,除了在编译时,没有办法以编程方式设置限制(但我很高兴被证明是错误的)。

于 2014-06-04T13:32:14.693 回答