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
的工作方式類似,但是速度更快,因爲不返回對象就可以對其進行更多優化。
如果要插入許多對象,建議的方法是使用insert
或insertOrUpdate
。
List<User> users = Arrays.asList(new User("John"), new User("Jane"));
realm.beginTransaction();
realm.insert(users);
realm.commitTransaction();
7.2 交易區塊
您可以使用executeTransaction方法代替手動跟蹤beginTransaction,commitTransaction
和cancelTransaction
的方法,該方法將自動處理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.
}
});
OnSuccess
和OnError
回調都是可選的,但是如果提供,則分別在事務成功或失敗時調用它們。回調由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");
}
});
這樣只能直接在對象上更新字段。 鏈接的字段或列表元素無法使用這些方法更新。