在两个线程中并发执行两个 SQLite 事务

发布于 2024-11-26 03:34:36 字数 730 浏览 1 评论 0原文

我的 Android 应用程序中有一个特定的更新方法,它会生成大量数据 - 多达数百个数据库条目。 除了 UI 线程之外,我还有一个后台服务。两个线程都必须执行 update 方法,有时甚至同时执行 - 基本上,这是关于生成和缓存要显示的数据。 UI和后台服务都需要这些数据。

目前,我已将方法的执行包装在 ORMLite 事务中,该事务映射到普通的 SQLite 事务。然而,我担心有一天,当某些竞争条件搞乱数据缓存时,这会咬我的屁股。

问题:SQLite 事务是否可以保护我免受并发执行的影响,或者我应该实现某种在生成器方法启动时生成的工作线程,或者在生成器方法已经运行时阻塞?

更新:

我决定不依赖 SQLite 逻辑来保护我的高级 Java 方法。对我来说,解决方案如下:

  • synchronized 包装方法的生成部分
  • 引入一个变量,用于跟踪上次执行该方法的时间(在方法末尾设置,因此它是标记执行结束)
  • synchronized 部分中的第一件事是检查上次执行是否在特定阈值内(例如过去 <= 100ms)
    • 如果是,则跳过生成
    • 如果不是,则执行生成

这样就不会发生重复生成,因为当同时从两个线程访问该方法时,第一个会生成,但第二个不会。对我来说最重要的部分是它仍然处于阻塞状态,因为两个线程都依赖于调用该方法后发生的生成。

I have a certain update method in my Android App, which generates quite an amount of data - up to hundreds of database entries.
I also have a background service, aside from the UI thread. Both threads have to execute the update method, sometimes even at the same time - basically, this is about generating and caching data to display. Both the UI and background service need this data.

Currently, I have wrapped the method's execution in an ORMLite transaction, which maps to an ordinary SQLite transaction. However, I am afraid that this will bite me in the butt one day, when some race condition screws up the data cache.

The question: Do SQLite transactions protect me from concurrent execution, or should I rather implement some kind of worker thread which is spawned when the generator-method shall start, or blocking if the generator-method is already running?

UPDATE:

I have decided to not rely on SQLite logic for the protection of my high-level Java method. The solution was for me as follows:

  • Wrap the generating part of the method with synchronized
  • Introduce a variable which tracks the last time of executing the method (set at the end of the method, so it is the marker of execution END)
  • First thing in the synchronized section, check if the last execution is in a specific threshold (e.g. <= 100ms in the past)
    • If yes, skip generation
    • If no, perform generation

In this way, duplicate generation should not take place, since when the method is accessed from two threads at the same time, the first will generate, but the second will not. The most important part for me here is that it is still blocking, since both threads rely on the generation having taken place after they have called the method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

抽个烟儿 2024-12-03 03:34:36

编辑:

我的以下陈述似乎是错误的:根据许多人的说法,SQLite 实现是线程安全的。然而,我曾经经历过线程问题,特别是在测试数据库访问时,但我认为这一定是由我的代码中的其他因素引起的。

抱歉回答有误导性。

起源:

好问题!

这里你应该非常小心,因为标准的Android数据库访问对象(例如SQLiteDatabaseCursor等)默认情况下不是线程安全的。甚至 ContentProvider 似乎也无法为您提供完整的保护,除非您明确地在考虑多线程的情况下编写它们。

根据 关于 ContentProvider 和线程的 Android 文档(几乎在页面末尾) :

“由于这些方法 [update() 是函数之一] 可能会同时从任意数量的线程调用,因此它们也必须实现为线程安全的。”< /p>

我不知道 SQLiteDatabases 是否有任何显式锁定机制(如锁定实际数据库文件)。我假设事务本身会锁定,至少是您访问数据库所用的句柄。我不知道对于数据库有多个句柄的情况,情况如何。

也许您可以尝试实现一些单例对象(也许是ContentProvider?)来访问您的数据库,但即使如此,我想您也必须管理某种“请求队列”。

您还应该考虑从 UI 线程对文件系统(数据库位于文件系统上)进行任何调用。无法保证数据库会及时答复,并且您可能会遇到 ANR(特别是当您编写 “...这会生成相当多的数据” 时)。

EDIT:

It seems I'm wrong in my below statement: The SQLite implementation is, according to many, thread safe. I have, however, bitterly experienced threading issues, especially when testing database access, but that must have been caused by other factors in my code then, I assume.

Sorry for the misleading answer.

ORIGIN:

Good question!

You should be very careful here because the standard Android database access objects (such as SQLiteDatabase, Cursor etc) are not thread-safe by default. Not even ContentProvider's seem to give you a complete protection unless you explicitly write them with multithreading in mind.

According to Android documentation on ContentProvider's and threading (almost at the end of the page):

"Because these methods [update() is one of the functions] might be called from any number of threads at the same time, they too must be implemented to be thread-safe."

I don't know if there is any explicit locking mechanism to SQLiteDatabases (as in locking the actual database file). I would assume that a transaction itself would lock, at least the very handle you access your database with. I don't know what is true for the case where you have multiple handles to your database.

Maybe you could try to implement some singleton object (A ContentProvider maybe?) to access your database with, but even then you'd have to manage some sort of "request queue" I suppose.

You should also consider not to make any calls to the file system (the database is on the file system) from the UI-thread, what-so-ever. There is no guarantee that the database will answer in time and you're likely to end up with an ANR (especially as you write "...which generates quite an amount of data").

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文