【问题标题】:Will these two Realm transactions interfere with eachother这两个 Realm 交易会不会互相干扰
【发布时间】:2017-10-27 02:06:42
【问题描述】:

我假设两个 Realm 事务不会相互干扰,因为这就是事务的用途吗?但鉴于我不是数据库/领域专家,我需要对此进行确认,以便我可以尽快继续我项目的其他部分。

我正在为失败的 HTTP 请求制作后台上传程序。每个请求在 Realm 中都有一个类,其对象是该类型的失败请求。还有一个名为“RequestUploadStatus”的类,它有一个名为“needsUpload”的字段,其对象维护给定请求类是否有需要上传的对象。

例如

评论
12、《你好》
45,“漂亮的衬衫”

图片

请求上传状态
[CommentClassId],真
[图像类 ID]。假的

我不确定这是否是最好的方法,但现在让我们假设它是。

所以,我想要避免的(假设有多个线程)是请求类之一的 RequestUploadStatus 具有错误的“needsUpload”值,例如如果没有要上传的对象,则为 true;如果有要上传的对象,则为 false。所以更具体地说,给出以下代码:如果 upload 事务正在循环通过 RealmResults 是 schedule 事务被阻止添加新对象以上传并为此设置“needsUpload”请求类。

安排交易

                    realm.executeTransaction(new Realm.Transaction() {
                        @Override
                        public void execute(Realm realm) {

                            EntityUploadStatus entityUploadStatus = realm.where(EntityUploadStatus.class).equalTo("entityId", entityClassIdMap.entityId).findFirst();
                            entityUploadStatus.uploadNeeded = true;

                            //a comment or image or whatever
                            realm.insertOrUpdate(entity);

                        }
                    });

上传交易

                          realmInstance.executeTransaction(new Realm.Transaction() {

                            @Override
                            public void execute(Realm realm) {

                                RealmResults<RealmObject> realmObjects = realmInstance.where(realmClass).findAll();

                                for(int i = 0; i < realmObjects.size(); i++) {

                                    RealmObject realmObject = realmObjects.get(i);

                                    Boolean success = uploadObject(realmObject, classToUpload.entityId);

                                    if(success)
                                    {

                                        realmObject.deleteFromRealm();

                                        if (i == realmObjects.size())
                                        {
                                            //last one successfully uploaded, set status to uploaded
                                            EntityUploadStatus entityUploadStatus = realm.where(EntityUploadStatus.class).equalTo("entityId", entityClassIdMap.entityId).findFirst();
                                            entityUploadStatus.uploadNeeded = false;

                                        }
                                    }
                                    else
                                        break;


                                }

                            }
                        });

代码未经测试,甚至可能无法编译,但我确定你明白了。

【问题讨论】:

  • 我们在谈论什么版本的 Realm?我的答案取决于它。
  • 我使用的是 3.7.2

标签: android realm


【解决方案1】:

此答案适用于 0.88.3 以下和 3.0.0 以上的任何版本。

你目前的提议有一个主要问题:

realmInstance.executeTransaction(new Realm.Transaction() {
  @Override
  public void execute(Realm realm) {
      RealmResults<RealmObject> realmObjects = realmInstance.where(realmClass).findAll();
      for(int i = 0; i < realmObjects.size(); i++) { // <-- !!!
          RealmObject realmObject = realmObjects.get(i);
          Boolean success = uploadObject(realmObject, classToUpload.entityId);
          if(success) {
              realmObject.deleteFromRealm(); // <-- !!!

在事务中,您看到的RealmResults 始终是可能的最新版本,包括您所做的任何会修改结果集元素的更改。

在这种情况下,您在直接迭代结果的同时删除项目,使用一个简单的循环:这意味着您将跳过元素,因为即使您删除项目也会增加索引(并且基础结果集具有该项目已删除)!

所以你应该这样做:

RealmResults<RealmObject> realmObjects = realmInstance.where(realmClass).findAll();
for(RealmObject obj : realmObjects) { // 3.0.0+

RealmResults<RealmObject> realmObjects = realmInstance.where(realmClass).findAll();
for(int i = realmObjects.size() - 1; i >= 0; i--) { // 0.88.3 and below

RealmResults<RealmObject> realmObjects = realmInstance.where(realmClass).findAll();
OrderedRealmCollection<RealmObject> snapshot = realmObjects.createSnapshot(); // <-- !!!
for(int i = 0; i < snapshot.size(); i++) {  // <-- !!!
    RealmObject realmObject = snapshot.get(i);

无论如何,事务是跨线程阻塞的,而且跨进程(2.0.0+),在给定时间只能有一个打开的写事务打开。

因此事务无法读取/操作无效/过时的数据。

【讨论】:

  • 好的,很有趣。 createSnapshot() 看起来对我有用。它不需要是活的。什么是“写”交易?还有其他种类吗?我的帖子中的两个交易都是“写”交易,即使它们已经读过?
  • 好吧,从技术上讲,realm.beginTransaction() (+commit/cancel) 和 realm.executeTransaction()(根据需要调用 begin/commit/cancel)都是 写入事务。如果你做一个简单的循环,那么你需要创建快照,否则你会跳过元素。在写事务中,您总是读取最新的可能数据。在事务内部时,每个更改都立即在 RealmResults 中可见。这有点棘手,但很有意义。
  • 好的,非常感谢。我做了一些测试,我认为我现在有足够的信心继续进行。
  • 很好的回答! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-09
  • 2013-05-27
  • 1970-01-01
相关资源
最近更新 更多