Realm(Java)数据库使用文档(Writes)


Realm(Java)数据库使用文档(目录)

与读取操作不同,Realm中的写入操作必须包装在事务中。在写操作结束时,您可以提交事务或取消事务。提交事务会将所有更改写入磁盘(如果Realm已同步,则将其排队以便与Realm对象Server同步)。如果取消写事务,则所有更改都将被丢弃。事务是“全有还是全无”:事务中的所有写入都成功,或者没有一个生效。这有助于确保数据的一致性,并提供线程安全性。

// 获取一个Realm实例
Realm realm = Realm.getDefaultInstance();

realm.beginTransaction();

//... 在此处添加或更新对象 ...

realm.commitTransaction();

或者通过取消交易放弃更改:

realm.beginTransaction();
User user = realm.createObject(User.class);

//  ...

realm.cancelTransaction();

写事务相互阻塞。如果您同时在UI和后台线程上创建写事务,则可能导致ANR错误。为避免这种情况,请在UI线程上创建写入事务时使用异步事务

如果交易中发生异常,则您将丢失该交易中的更改,但是Realm本身不会受到影响(或损坏)。如果发现异常并且应用继续运行,则需要取消事务。如果使用executeTransaction,则会自动发生。

借助Realm的MVCC架构,在打开写入事务时不会阻止读取。除非您需要一次从多个线程同时进行事务处理,否则您可以选择比许多细粒度事务处理更多工作的大型事务。当您向Realm提交写事务时,该Realm的所有其他实例将得到通知并自动更新

Realm中的读写访问权限为ACID

7.1 创建对象

将createObject方法包装在写事务中。

realm.beginTransaction();
User user = realm.createObject(User.class); // 创建一个新对象
user.setName("John");
user.setEmail("[email protected]");
realm.commitTransaction();

如果首先创建一个对象实例,然后使用copyToRealm将其添加到Realm中,那么您也应该将copy操作包装在一个事务中。Realm支持任意数量的自定义构造函数,只要其中一个是公共无参数构造函数即可。

User user = new User("John");
user.setEmail("[email protected]");

// 将对象复制到Realm。 任何进一步的更改都必须在realmUser上发生
realm.beginTransaction();
User realmUser = realm.copyToRealm(user);
realm.commitTransaction();

请记住,Realm仅管理返回的对象(在此示例中为realmUser),而不管理最初复制的对象(用户)。要更改数据库中的对象,请更改返回的副本,而不是原始副本。

如果只对插入对象感兴趣,而不是立即使用托管副本,则可以改用insert。这与copyToRealm的工作方式类似,但是速度更快,因为不返回对象就可以对其进行更多优化。

如果要插入许多对象,建议的方法是使用insertinsertOrUpdate

List<User> users = Arrays.asList(new User("John"), new User("Jane"));

realm.beginTransaction();
realm.insert(users);
realm.commitTransaction();

7.2 交易区块

您可以使用executeTransaction方法代替手动跟踪beginTransaction,commitTransactioncancelTransaction的方法,该方法将自动处理begin / commit,并在发生错误时取消。

realm.executeTransaction(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
        User user = realm.createObject(User.class);
        user.setName("John");
        user.setEmail("[email protected]");
    }
});

7.3 异步事务

由于事务被其他事务阻止,因此您可能需要在后台线程上进行写操作,以避免阻止UI线程。通过使用异步事务,Realm将在后台线程上运行该事务。

realm.executeTransactionAsync(new Realm.Transaction() {
    @Override
    public void execute(Realm bgRealm) {
        User user = bgRealm.createObject(User.class);
        user.setName("John");
        user.setEmail("[email protected]");
    }
}, new Realm.Transaction.OnSuccess() {
    @Override
    public void onSuccess() {
        // Transaction was a success.
    }
}, new Realm.Transaction.OnError() {
    @Override
    public void onError(Throwable error) {
        // Transaction failed and was automatically canceled.
    }
});

OnSuccessOnError回调都是可选的,但是如果提供,则分别在事务成功或失败时调用它们。回调由Looper控制,因此仅在Looper线程上允许回调。

RealmAsyncTask transaction = realm.executeTransactionAsync(new Realm.Transaction() {
            @Override
            public void execute(Realm bgRealm) {
                User user = bgRealm.createObject(User.class);
                user.setName("John");
                user.setEmail("[email protected]");
            }
        }, null);

如果需要在事务完成之前退出Activity/Fragment,则RealmAsyncTask对象可以取消任何待处理的事务。如果回调更新了UI,则忘记取消交易可能会使应用程序崩溃!

public void onStop () {
    if (transaction != null && !transaction.isCancelled()) {
        transaction.cancel();
    }
}

7.4 更新strings和字节数组byte arrays

由于Realm会在整个字段上运行,因此无法直接更新字符串或字节数组的各个元素。取而代之的是,您需要阅读整个字段,对单个元素进行修改,然后再将其写回到transaction块中。

realm.executeTransaction(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
        bytes[] bytes = realmObject.binary;
        bytes[4] = 'a';
        realmObject.binary = bytes;
    }
});

7.5 批量更新

如果您需要一次更新许多对象,那么最有效的方法是进行查询以查找对象并使用RealmResults.setX()方法之一,其中X是您要更新的字段类型。

// Updating a boolean field
realm.executeTransaction(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
        RealmResults<Person> persons = realm.where(Person.class).equalTo("invited", false).findAll();
        persons.setBoolean("invited", true);
    }
});

也可以使用称为RealmResults.setValue(String fieldName,Object value)的通用set方法,该方法会自动检测输入的类型并进行适当的转换。这类似于DynamicRealmObject.setX()DynamicRealmObject.setValue()的行为。使用RealmResults.setValue()比使用特定的类型化方法要慢。

// Updating a boolean field using automatic input conversion as needed.
realm.executeTransaction(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
        RealmResults<Person> persons = realm.where(Person.class).equalTo("invited", false).findAll();
        persons.setValue("invited", "true"); 
    }
});

这样只能直接在对象上更新字段。 链接的字段或列表元素无法使用这些方法更新。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章