SQLiteDatabase多线程锁定模式

2023-11-27

我使用此类来管理与底层 SQLiteDatabase 的连接

public class BasicDataSource {

    protected DatabaseHandler dbHelper;
    protected volatile SQLiteDatabase readable_database;
    protected volatile SQLiteDatabase writable_database;
    protected Object read_lock = new Object();
    protected Object write_lock = new Object();
    protected Context context;

    protected BasicDataSource(Context ctx) {
        dbHelper = DatabaseHandler.getInstance(ctx);
        getReadableDatabase();
        dbHelper.onCreate(getWritableDatabase());
        this.context = ctx;
    }

    public synchronized void close() {
        dbHelper.close();
    }

    protected void closeInsertHelpers(InsertHelper... helpers) {
        for (InsertHelper ih : helpers) {
            if (ih != null)
                ih.close();
        }
    }

    protected SQLiteDatabase getReadableDatabase() {
        synchronized (read_lock) {
            if (readable_database == null || !readable_database.isOpen()) {
                readable_database = dbHelper.getReadableDatabase();
            }
            return readable_database;
        }
    }

    protected SQLiteDatabase getWritableDatabase() {
        synchronized (write_lock) {
            if (writable_database == null || !writable_database.isOpen()) {
                writable_database = dbHelper.getWritableDatabase();
            }
            return writable_database;
        }
    }

    protected synchronized void open() throws SQLException {
        getReadableDatabase();
        getWritableDatabase();
    }
}

它包含两个锁,一个用于读取,第二个用于写入。 但我仍然偶尔会遇到这种异常:

java.lang.RuntimeException: An error occured while executing doInBackground()
        at android.os.AsyncTask$3.done(AsyncTask.java:299)
        at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
        at java.util.concurrent.FutureTask.run(FutureTask.java:137)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
        at java.lang.Thread.run(Thread.java:856)
Caused by: android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5): , while compiling: PRAGMA journal_mode
        at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
        at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:882)
        at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:627)
        at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:313)
        at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:287)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
        at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
        at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
        at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
        at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:804)
        at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:789)
        at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
        at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:804)
        at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:221)
        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:224)
        at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
        at com.mycompany.myapplication.sql.BasicDataSource.getWritableDatabase(BasicDataSource.java:57)
        at com.mycompany.myapplication.sql.datasources.SomeDataSource.fillUpDatabaseMethod(SomeDataSource.java:264)
        at com.mycompany.myapplication.sql.datasources.SomeDataSource.renewCacheMethod(SomeDataSource.java:560)
        at com.mycompany.myapplication.activities.lists.ListsActivity$Worker.doInBackground(ListsActivity.java:315)
        at com.mycompany.myapplication.activities.lists.ListsActivity$Worker.doInBackground(ListsActivity.java:1)
        at android.os.AsyncTask$2.call(AsyncTask.java:287)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
        ... 4 more
android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5): , while compiling: PRAGMA journal_mode
        at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
        at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:882)
        at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:627)
        at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:313)
        at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:287)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
        at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
        at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
        at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
        at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:804)
        at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:789)
        at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
        at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:804)
        at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:221)
        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:224)
        at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
        at com.mycompany.myapplication.sql.BasicDataSource.getWritableDatabase(BasicDataSource.java:57)
        at com.mycompany.myapplication.sql.datasources.SomeDataSource.fillUpDatabaseMethod(SomeDataSource.java:264)
        at com.mycompany.myapplication.sql.datasources.SomeDataSource.renewCacheMethod(SomeDataSource.java:560)
        at com.mycompany.myapplication.activities.lists.ListsActivity$Worker.doInBackground(ListsActivity.java:315)
        at com.mycompany.myapplication.activities.lists.ListsActivity$Worker.doInBackground(ListsActivity.java:1)
        at android.os.AsyncTask$2.call(AsyncTask.java:287)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
        at java.util.concurrent.FutureTask.run(FutureTask.java:137)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
        at java.lang.Thread.run(Thread.java:856)

这意味着,当尝试获取 getWritableDatabase 中的锁时,数据库以某种方式被锁定。

我的 SQLiteOpenHelper 是单例模式,并且 DataSources 仅使用 BasicDataSource 作为父类。

我可以做哪些改进来避免显示代码中的 SQLiteDatabaseLockedException?


在 SQLite 中,可以有任意多个读取器,但任何写入器都会阻止所有其他读取器和写入器。

您必须对读取器和写入器使用同一个锁。

请注意,只要您实际访问数据库,就必须保持锁定。


如果您想支持多个读取器,请使用实现的锁ReadWriteLock, 例如ReentrantReadWriteLock。像这样的东西:

class MyData {
    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    private final Lock r = rwl.readLock();
    private final Lock w = rwl.writeLock();

    public Data ReadSomething(int id) {
        r.lock();
        try {
            Cursor c = readableDatabase.query(...);
            return c.getString(0);
        } finally {
            r.unlock();
        }
    }

    public void ChangeSomething(int id, int value) {
        w.lock();
        try {
            writeableDatabase.update(...);
        } finally {
            w.unlock();
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SQLiteDatabase多线程锁定模式 的相关文章

随机推荐

  • 与 SQL Server 建立连接时发生网络相关或特定于实例的错误

    我在 azurewebsites 上有一个简单的 mvc 网站 使用 VS internet 模板 与同一数据中心的 SQL Azure 数据库进行通信 此时的数据库只是做内置的SimpleMembership Provider 我已经从默
  • FFmpeg:在 Android Q 上无法使用文件描述符进行查找

    鉴于公共文件路径通常在具有范围存储的 Android Q 中不可用 我试图弄清楚如何使我的 FFmpeg 音频解码器使用文件描述符 而不将文件复制到我的应用程序的私有目录 我们可以使用中描述的方法轻松获取文件描述符Android Q 隐私更
  • 释放 GLKTextureLoader 分配的纹理(GLKTextureInfo 对象)

    对于 iOS 开发新手 尤其是 iOS 5 上的新 OpenGL 相关功能 如果我的问题非常基本 我深表歉意 我正在开发的应用程序旨在接收相机帧并通过 OpenGL ES 将它们显示在屏幕上 图形人员将接管此操作并添加我知之甚少的实际 Op
  • 像 PHP 一样使用 Request.Form 处理 HTML 输入元素数组

    我怎样才能在asp net上正确接收这些输入数组
  • jQuery 1.9.1 $.event.handle.apply 替代品

    我最近将我的一个项目更新到 jQuery 1 9 1 我无法再使用 event handle apply 方法 我搜索并发现 我可以放置jquery migrate js 我只是想确认一下是否还有其他选择 我的 google fu 在这里失
  • MongoDB GridFs用C#,如何存储图像等文件?

    我正在开发一个以 mongodb 作为后端的网络应用程序 我想让用户将图片上传到他们的个人资料中 例如链接的个人资料图片 我正在使用带有 MVC2 的 aspx 页面 并且我读到 GridFs 库用于将大型文件类型存储为二进制文件 我到处寻
  • ActionName 的目的

    使用 ActionName 属性为操作方法设置别名有什么好处 在为用户提供使用其他名称调用操作方法的选项方面 我确实没有看到它有多大好处 指定别名后 用户只能使用别名调用操作方法 但如果这是必需的 那么为什么用户不更改操作方法的名称而不是为
  • 当 reshape 无法猜测时变变量的名称时,重塑 r 中的数据

    我有一个包含超过 1500 列的宽格式数据集 由于许多变量都是重复的 我想将其重塑为长形式 然而 r 抛出一个错误 Error in guess varying Failed to guess time varying variables
  • 如何在 C#.NET 中跨线程锁定控制台?

    我有一个logger处理各种带有漂亮颜色的信息显示的类 是的 但是 由于它写入控制台分开的步骤 即 将颜色设置为红色 写入文本 将颜色设置为灰色 写入文本 以便呈现 错误 描述 错误为红色 但我有一个多线程应用程序 因此这些步骤可能会混淆并
  • 从 SQL Server 列获取 XML 节点作为逗号分隔列表

    我有一个数据存储在 xml 列中 并且需要一个以逗号分隔的子节点列表 使用下面的脚本 我只能得到 A B C 请帮助我使用 xquery 获取 A B C 简单地用逗号替换空格没有帮助 因为我们的数据里面有空格 create table T
  • 查找给定整数序列的排列数,这些排列产生相同的二叉搜索树

    给定一个整数数组arr 5 6 1 当我们以相同的顺序使用此输入构建 BST 时 我们将 5 作为根 6 作为右子节点 1 作为左子节点 现在 如果我们的输入更改为 5 1 6 我们的 BST 结构仍然相同 那么给定一个整数数组 如何找到输
  • YouTube Android 播放器 API 在新的 YouTube 版本中解组时抛出“BadParcelableException ClassNotFoundException:asc”

    向 YouTube Android Player API 库工程师提交错误 请参阅 android youtube api 标签 在过去的一个半星期里 我注意到这个奇怪的 BadParcelableException 在我们的应用程序中稳步
  • 为什么我在运行 Python 时在 Spyder 中收到“启动内核时发生错误”?

    我已经在 Windows 8 1 系统中安装了 Anaconda python 3 7 但是 在从 Spyder 控制台运行 Python 代码时 出现以下错误 An error occurred while starting the ke
  • 从 char* 获取 istream

    我有一个 char 和从库接收的数据长度 我需要将数据传递给采用 istream 的函数 我知道我可以创建一个字符串流 但这将复制所有数据 而且 数据肯定会有 0 因为它是一个 zip 文件 并且创建字符串流将获取数据 直到我认为第一个 0
  • 如何使 JScrollPane 滚动以跟随输入焦点?

    我有一个带有大面板的 Swing 应用程序 该面板被包裹在JScrollPane 用户通常通过选项卡在面板的子组件之间移动 因此当他们使用选项卡切换到视图之外的某些内容时 我希望滚动窗格自动滚动 以便具有输入焦点的组件始终可见 我尝试过使用
  • Delphi自定义动画-碰撞检测

    我正在使用自定义绘图 2D 动画 并且正在尝试找出如何检测移动物体何时与地图中的墙壁碰撞 用户按住键盘上的方向键来移动对象 地图存储为点的数组结构 地图中的墙壁可能是有角度的 但没有弯曲的墙壁 使用地图结构 FMap TMap 在我下面的代
  • 触摸后关闭弹出窗口

    我在我的里面创建了一个弹出窗口MainViewController当使用某个按钮触摸时UIPopoverPresentationController并像 WWDC 2014 中所示那样设置它的委托 方法如下 MainViewControll
  • C 和 C++ 中带有 const 限定符的数组指针

    考虑以下程序 int main int array 9 const int p2 9 array 它在 C 中编译得很好 参见现场演示here 但在 C 中编译失败 默认情况下 GCC 会给出以下警告 参见现场演示here prog c I
  • Scala REPL:如何查找函数类型?

    在 Scala REPL 中可以找到值类型 scala gt val x 1 x Int 1 scala gt t x Int 然而 Scala REPL 不显示函数的类型信息 scala gt def inc x Int x 1 inc
  • SQLiteDatabase多线程锁定模式

    我使用此类来管理与底层 SQLiteDatabase 的连接 public class BasicDataSource protected DatabaseHandler dbHelper protected volatile SQLite