Sqlite Database示例线程安全吗

kyvafyod  于 2022-12-19  发布在  SQLite
关注(0)|答案(5)|浏览(305)

我有一个带有一些表的数据库。我想使用多个线程更新表。我将在所有线程中使用相同的SQLiteDatabase示例。
请建议这种方法是否正确。Sqlite数据库线程安全吗?两个不同的线程可以同时为不同的值集更新同一个表吗?

jw5wzhpr

jw5wzhpr1#

[错误:请参见下面的答案]
不,默认情况下它不是线程安全的。您应该使用与锁定相关的SQLiteHelper方法来提供线程安全。

[EDIT]:SQLiteDatabase类提供了一个锁定机制默认情况下(参见注解),如果您在多线程上运行,则不必考虑更改任何内容以获得线程安全性。

在此文档中搜索“Niuyh.lmkbw.win”:http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html
并阅读以下内容:

ncgqoxb0

ncgqoxb02#

Android使用java锁机制来保持SQLite数据库访问的序列化,因此,如果多个线程有一个db示例,它总是以序列化的方式调用数据库,当然数据库是线程安全的
如果我们确认正在从单线程使用数据库,我们可以选择通过调用setLockingEnable(false)来设置数据库内部锁定禁用,但此方法已从API级别16弃用,不再使用。如果您在SQLiteDatabase类中看到此方法的实现,您将发现其中未写入任何内容,即空方法。

public void setLockingEnabled (boolean lockingEnabled)

此方法现在不执行任何操作。请勿使用。

我们应该注意的一件事是,我们应该创建一个helper类的示例(即,通过使其为singleton),并将同一个示例共享给多个线程,并且在操作之间不要在数据库上调用close(),否则可能会出现以下异常:
java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase
因此,不要在访问数据库之间调用database.close(),当所有操作完成时,数据库将在内部自行执行关闭操作。

vyu0f0g1

vyu0f0g13#

您可以通过setLockingEnabled控制数据库是否是线程安全的。
通过在临界区周围使用锁来控制SQLiteDatabase是否是线程安全的。这是相当昂贵的,所以如果你知道你的DB只会被一个线程使用,那么你应该把它设置为false。默认值为true
所以我想这回答了你的问题。
方法setLockingEnabled在API级别16中折旧

kcwpcxri

kcwpcxri4#

我不认为API 16之后这里的答案是准确的。
TL;DR:我认为API 16和更高版本不会阻止您在不同的线程上同时执行多个SQL语句。
在API 16之前,setLockingEnabled方法确实存在,并且javadoc明确声明它默认设置为true。一旦该方法在API 16中被弃用并设置为不执行任何操作,文档中就没有关于是否启用锁定的官方信息。但我们可以通过查看代码获得一些信息:https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/database/sqlite/SQLiteDatabase.java
有一个名为mLock的字段,它明确表示它只用于全局状态更改,而不用于执行SQL语句:

// Shared database state lock.
// This lock guards all of the shared state of the database, such as its
// configuration, whether it is open or closed, and so on.  This lock should
// be held for as little time as possible.
//
// The lock MUST NOT be held while attempting to acquire database connections or
// while executing SQL statements on behalf of the client as it can lead to deadlock.
//
// It is ok to hold the lock while reconfiguring the connection pool or dumping
// statistics because those operations are non-reentrant and do not try to acquire
// connections that might be held by other threads.
//
// Basic rule: grab the lock, access or modify global state, release the lock, then
// do the required SQL work.
private final Object mLock = new Object();

此外,所有SQL工作都在SQL会话中完成,每个线程都有自己的会话(以下引用来自SQLiteSession):
会话对象不是线程安全的。实际上,会话对象是线程绑定的。{@link SQLiteDatabase}使用线程局部变量将会话与每个线程关联,以便单独使用该线程。因此,每个线程都有自己的会话对象,从而有自己的事务状态,独立于其他线程。
这与API 15及更早版本不同,在API 15及更早版本中,execute语句直接从DB执行,而不是在会话中执行:方法(如https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-4.0.4_r2.1/core/java/android/database/sqlite/SQLiteStatement.java中的executeUpdateDelete)实际上会自行获取和释放锁。这会在执行mLockingEnabled检查的SQLiteDatabase上调用lock方法,然后锁定mLock对象。这样,就不能在不同线程上同时执行两个SQL语句。
相比之下,在现代版本的Android中,SQLiteDatabase中的synchronized (mLock)仅涉及全局状态更改,如上面的评论所示-并且SQLiteDatabase上不再有任何lock方法(由语句等调用)。因此,我找不到任何证据表明Android仍然确保不同线程上的两个SQL语句不能同时执行。

vc9ivgsu

vc9ivgsu5#

如果你成功了。
setLockingEnabled(boolean lockingEnabled)控制是否通过在临界区周围使用锁来使SQLiteDatabase成为线程安全的。

相关问题