Android:使用 ContentResolver 时的 SQLite 事务
目标:从 XML 数据刷新数据库
过程:
- 启动事务
- 删除表中的所有现有行
- 根据解析的 XML 插入行的每个主要元素进入主表并获取 PK
- 每个主元素的每个子元素 插入 记录到第二个表中,提供上一步的 FK
- 提交事务
就数据库操作而言,这是相当标准的东西。问题是 CRUD 操作不是在 ContentProvider
内完成的,而是使用 ContentResolver
完成的,因此插入示例看起来像 resolver.insert(CONTENT_URI, contentValues)
。 ContentResolver API 似乎没有与事务相关的任何内容,并且我无法使用 bulkInsert
因为我间歇性地插入 2 个表(另外我希望在交易也是如此)。
我正在考虑使用 registerContentObserver
将自定义的 ContentProvider
注册为侦听器,但由于 ContentResolver#acquireProvider
方法被隐藏,我如何获得正确的引用?
我运气不好吗?
The goal: refresh database from XML data
The process:
- Start transaction
- Delete all existing rows from the tables
- Per each main element of parsed XML insert row into main table and get PK
- Per each child of the main element insert record into 2nd table providing FK from the previous step
- Commit transaction
Pretty standard stuff as far as db operations. The problem is that CRUD operations are not done within ContentProvider
but rather using ContentResolver
so the insert for example looks like resolver.insert(CONTENT_URI, contentValues)
. The ContentResolver API doesn't seem to have anything pertained to transaction and I cannot use bulkInsert
since I'm inserting in 2 tables intermittently (plus I want to have delete
inside the transaction as well).
I was thinking of registering my customized ContentProvider
as listener by using registerContentObserver
but since ContentResolver#acquireProvider
methods are hidden how do I obtain the right reference?
Am I out of luck?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我在 Google I/O 应用程序的源代码中看到,它们重写了
ContentProvider
的applyBatch()
方法并在其中使用事务。因此,您创建一批ContentProviderOperation
,然后调用getContentResolver().applyBatch(uri_authority, batch)
。我打算使用这种方法来看看它是如何工作的。我很好奇是否还有其他人尝试过。
I've seen that in the source code of Google I/O application, they override
ContentProvider
'sapplyBatch()
method and use transactions inside of it. So, you create a batch ofContentProviderOperation
s and then callgetContentResolver().applyBatch(uri_authority, batch)
.I'm planning to use this approach to see how it works. I'm curious if anyone else has tried it.
正如 kaciula 提到的,自 Android 2.1 以来,可以通过使用 ContentProviderOperation 相当干净地进行基于事务的多表插入。
构建 ContentProviderOperation 对象时,可以调用 .withValueBackReference(fieldName, refNr)。当使用 applyBatch 应用该操作时,结果是通过 insert() 调用提供的 ContentValues 对象将注入一个整数。该整数将使用 fieldName 字符串作为键控,其值是从先前应用的 ContentProviderOperation 的 ContentProviderResult 中检索的,由 refNr 索引。
请参考下面的代码示例。在示例中,在表 1 中插入一行,然后在表 2 中插入该行时,将生成的 ID(在本例中为“1”)用作值。为简洁起见,ContentProvider 未连接到数据库。在 ContentProvider 中,有适合添加事务处理的打印输出。
It is possible to do transaction based multi table inserts rather cleanly since Android 2.1 by using ContentProviderOperation, as mentioned by kaciula.
When you build the ContentProviderOperation object, you can call .withValueBackReference(fieldName, refNr). When the operation is applied using applyBatch, the result is that the ContentValues object that is supplied with the insert() call will have an integer injected. The integer will be keyed with the fieldName String, and its value is retrieved from the ContentProviderResult of a previously applied ContentProviderOperation, indexed by refNr.
Please refer to the code sample below. In the sample, a row is inserted in table1, and the resulting ID (in this case "1") is then used as a value when inserting the row in table 2. For brevity, the ContentProvider is not connected to a database. In the ContentProvider, there are printouts where it would be suitable to add the transaction handling.
好吧 - 所以这不会漫无目的:我能想到的唯一方法是将 startTransaction 和 endTransaction 编码为基于 URL 的查询请求。类似于
ContentResolver.query(START_TRANSACTION, null, null, null, null)
。然后在ContentProvider#query
中根据注册的URL调用开始或结束事务All right - so this does not dingle aimlessly: the only way I can think of is to code startTransaction and endTransaction as URL-based query requests. Something like
ContentResolver.query(START_TRANSACTION, null, null, null, null)
. Then inContentProvider#query
based on the registered URL call start or end transaction您可以获取内容提供程序对象本身的实现(如果在同一进程中,提示:您可以使用 multiprocess="true" 或 process="" http://developer.android.com/guide/topics/manifest/provider-element.html) 使用 ContentProviderClient.getLocalContentProvider () 可以转换为您的提供程序实现,它可以提供额外的功能,例如关闭和删除数据库的 Reset(),您还可以使用 save() 和 close() 方法返回自定义 Transaction 类实例。
然后:
You can get the implementation of the content provider object itself (if in the same process, hint: you can control the provider's process with multiprocess="true" or process="" http://developer.android.com/guide/topics/manifest/provider-element.html) using ContentProviderClient.getLocalContentProvider () which can be casted to your provider implementation which can provide extra functionality like a reset() that closes and deletes the database and you can also return a custom Transaction class instance with save() and close() methods.
Then: