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"); 
    }
});

這樣只能直接在對象上更新字段。 鏈接的字段或列表元素無法使用這些方法更新。

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