Android:多个线程写入SQLite数据库

5
在我的主活动的onCreate()方法中,我调用了dbManager的构造函数,然后调用打开函数创建一个SQLiteOpenHelper实例,最后在其上调用getWritableDatabase()。 在UIThread中,我向数据库添加记录并将这些记录保存到ArrayList中。另外两个线程检查ArrayList并进行操作,然后更新列表和数据库。 现在我想在UI中添加一个按钮,使用AsyncTask删除数据库和列表记录。 我读过SqliteOpenHelper对象只拥有一个数据库连接。因此,如果有一个helper实例,则只有一个db连接。该连接可以从多个线程中使用,并且SqliteDatabase对象使用Java锁来保持访问序列化。因此,如果有多个线程写入数据库,一个线程将等待前一个线程完成其操作吗? 添加新功能(全部删除)可能会创建问题,因为我必须避免其中一个线程尝试编辑不再存在的记录。如何实现我的目标?谢谢。

你应该实现消费者和生产者模式,这将帮助你构建请求队列,不要直接并行写入数据库。 - hackp0int
根据您的编辑实现方式而定,但 SQL 更新将返回 n,其中 n 是修改的项目数,如果没有与 where 子句匹配的记录,则完全可以为 0。 - njzk2
  1. 不应该在UI线程上执行数据库操作。
  2. 只有一个线程读写ArrayList。@IamStalker为什么不并行写入数据库?
- m0skit0
因为你必须要处理乐观并发,这是因为SQL-lite不支持并发。 - hackp0int
true,SQLite本身不支持并发,但是Android的SQLiteOpenHelper完美支持并发。您只需要确保所有线程都使用相同的实例即可! - Amir Uval
2个回答

4

数据库:

只要使用一个帮助程序,您无需进行任何操作即可实现线程安全。
在多线程应用程序中,您只需要在帮助程序的创建上使用synchronized
如果您想定义关键部分(多个原子操作),可以使用事务
将每个调用封装在getWritableDatabase()close(false)中:

public void doSomething() {
    SQLiteDatabase tdb = getWritableDatabase();
    dbInstance.writeSomething(tdb, 1);
    close(false);
}

通过这种方式,我可以让多个线程无障碍地读写数据库。

您的应用逻辑:

使用内存来跟踪对象状态,只将数据库用作存储。因此,如果一个线程从数据库中删除行 - 您可以立即更新内存中的对象,并相应地处理您的用户界面。
如果您的数据非常大,则可以仅在内存中保留SparseArray的脏行ID。
在此处同步某些操作可能会很有用。


数据库助手正在执行所有必要的同步操作以维护数据库完整性。与数据库无关的是,在应用程序逻辑中,开发人员可能需要在代码的关键部分进行同步,以维护业务逻辑的完整性。 - Amir Uval
没有这样的限制,一百个线程可以同时读写同一个数据库而不会出现任何问题。只需使用一个帮助程序。这并不是编写多线程应用程序时出现问题的地方。 - Amir Uval
参见 https://dev59.com/6XE95IYBdhLWcg3wCJNf#3689883 - 他所说的和我所说的一样:使用一个帮助程序实例,你的多线程应用就没问题了。 - Amir Uval
兄弟!你完全误解了整件事,这是一个提供者消费者队列,没有什么好谈的。 - hackp0int
让我们在聊天中继续这个讨论 - Amir Uval

0
如果我有多个线程在数据库上写入,一个线程会等待前一个线程完成操作吗?
不需要这样。请参见this以获取更多详细信息。无论如何,这取决于DB引擎,应该是透明的。
添加新功能(删除所有)可能会创建问题,因为我必须避免两个线程中的一个尝试编辑不存在的记录。我该如何实现我的目标?
只有一个线程更新DB。其他线程仅修改ArrayList-还要注意,因为ArrayList不是线程安全的,请考虑使用Collections#synchronizedList()。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接