SQLite中并发读/写和读取的策略

时间:2012-08-24 21:39:44

标签: concurrency sqlite

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

根据the document

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

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

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

有没有办法实现我的并发写作和阅读目标?

3 个答案:

答案 0 :(得分:19)

使用WAL mode。它支持并发读者和一位作家。

答案 1 :(得分:0)

对于Android,您可以使用WAL模式。 API(严重)支持它。更好的支持从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/

答案 2 :(得分:-6)

您的问题的简单答案是 - &#34;不可能&#34;

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

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

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

简单回答 -

您无法同时执行W-W,W-R,R-W操作。

(W - 写,R-读)

但是,您可以同时执行无限的R-R操作。

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

其中有一个使用数据库的特殊功能,即Transaction。

遵循ACID。

是原子性,一致性,隔离性,耐久性。

原子性 - 完成或不完整。

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

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

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

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

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

2

SQLite数据库文件被组织为页面。每个的大小 page是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的自定义构建 为您的应用程序。据我所知,没有办法设置 除编译时以编程方式限制(但我很高兴 被证明是错误的。)