Realm(Java)数据库使用文档(目录)
通过继承RealmObject
基类来创建Realm模型:
public class User extends RealmObject {
private String name;
private int age;
@Ignore
private int sessionId;
// IDE生成的标准getters和setters…
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public int getSessionId() { return sessionId; }
public void setSessionId(int sessionId) { this.sessionId = sessionId; }
}
Realm model字段支持public、protected和private修饰符以及自定义方法。
public class User extends RealmObject {
public String name;
public boolean hasLongName() {
return name.length() > 7;
}
@Override
public boolean equals(Object o) {
// Custom equals comparison
}
}
3.1 字段类型
Realm支持boolean、byte、short、int、long、float、double、String、Date
和byte[]
字段类型。数值类型byte、short、int
和long
在Realm中都映射为long
。除了这些标准字段类型之外,Realm还支持RealmObject
和RealmList <? extends RealmObject>
扩展为模型关系。
装箱的Boolean、Byte、Short、Integer、Long、 Float
和Double
也可以在模型类中使用。这些类型的值可能为null
。
3.2 必填字段
@Required
注解可用于标记Realm字段中禁止为空值,使其成为必填字段,而不是可选字段。 使用@Required只能注释Boolean、Byte、Short、Integer、Long、Float、Double、String、byte[]
和Date
。 如果将其添加到其他字段类型,编译将失败。
具有基本类型和RealmList
类型的字段是非必需的。RealmObject
类型的字段始终可以为空。
3.3 主键
使用@PrimaryKey
注解将字段标记为model的主键。字段类型必须是字符串(String
)或整数(byte, short、int、long、Byte、Short、Integer
和Long
)。 使用字符串字段作为主键会自动为该字段建立索引:字符串上的@PrimaryKey
注解隐式设置了@Index
注解。Realm不支持复合键,即使用多个字段作为单个主键。
使用主键可以使用copyToRealmOrUpdate()
或insertOrUpdate()
方法。它们查找具有给定主键的对象,然后更新它(如果具有该键的对象已经存在)或创建它(如果键不存在)。如果在没有主键的类上调用copyToRealmOrUpdate()
或insertOrUpdate()
,则会引发异常。
当您使用主键时,读取(查询)会稍微快一些,但是写入(创建和更新对象)会慢一些。 性能上的变化将取决于Realm数据集的大小。
请注意,Realm.createObject
返回一个新对象,其所有字段均设置为其默认值。 如果对象是具有主键的类,则可能会产生冲突(可能已经存在具有该主键集的对象)。 为避免这种情况,您可以创建一个非托管对象,设置其字段值,然后使用copyToRealm()
或insert()
将其添加到Realm:
final MyObject obj = new MyObject();
obj.setId(42);
obj.setName("Fish");
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
// 在Realm中创建一个新对象,或者如果该对象已经存在(相同的主键),则抛出异常。
// 更新具有相同主键的现有对象,或者如果没有主键的对象= 42,则创建一个新对象
realm.copyToRealmOrUpdate(obj);
}
});
除非@PrimaryKey
与@Required
注解结合使用,否则String
类型或装箱的整数(Byte,Short,Integer
和Long
)的主键可以具有null
值。
3.4 索引属性
要为字段建立索引,请像主键一样使用@Index
注解。这会使写入速度稍慢,但会使读取速度更快。(存储索引也会使您的Realm文件略大)最好仅在针对特定情况优化读取性能时才添加索引。
可以String、byte、short、int、long、boolean
和Date
字段使用索引。
3.5 忽略属性
如果您不想将model中的字段保存到Realm,请使用注解@Ignore
。例如,如果您的输入包含比model更多的字段,并且您不想有很多特殊情况来处理这些未使用的数据字段,则可以这样做。
标记为static
和transient
的字段始终被忽略,并且不需要@Ignore
注解。
3.6 计数器Counters
Realm提供MutableRealmInteger
作为特殊的整数类型。 MutableRealmInteger公开了一个附加API,可以在使用同步Realms
时更清楚地表达意图并生成更好的冲突解决步骤。
传统上,将通过读取一个值,对其进行递增并设置它来实现计数器(myObj.counter + = 1
)。 在异步情况下(例如,当两个客户端脱机时),不能好好工作,因为双方将读取一个值,例如10,对其进行递增,然后将该值存储为11。最终,当他们重新获得连接并尝试合并其值时 更改后,他们将同意计数器位于11而不是预期的12。
MutableRealmIntegers
由传统的整数类型支持,因此将字段从byte、short、int
或long
更改为MutableRealmInteger
时不需要迁移。
MutableRealmInteger
不是像Java中的原始数字类型那样的不可变类型标准。 它是一个实时对象,例如RealmObject,RealmResults
和RealmList
。这意味着写入Realm时,MutableRealmInteger
内部包含的值可以更改。 因此,必须将MutableRealmInteger
字段标记为final
。
public class Party extends RealmObject {
public final MutableRealmInteger guests = MutableRealmInteger.valueOf(0);
}
要更改计数器值,只需调用counter.increment()
或counter.decrement()
。
Party party = realm.where(Party.class).findFirst();
realm.beginTransaction();
party.guests.get(); // 0
party.guests.increment(1); // 1
party.guests.decrement(1); // 0
party.guests.increment(5); // 5
party.guests.decrement(1); // 4
realm.commitTransaction();
要重置计数器,可以使用counter.set()
为它分配一个新值。
调用set()可能会覆盖来自其他设备increment()和decrement()操作。正常的最后合并写入成功,因此仅在有损计数器可接受的情况下才应进行这些操作的混合。
Party party = realm.where(Party.class).findFirst();
realm.beginTransaction();
party.guests.set(0);
realm.commitTransaction();
3.7 覆盖属性名称
默认行为是Realm将使用model类中定义的名称作为名称来表示Realm文件内部的类和字段。 在某些情况下,您可能想要更改此行为:
- 支持具有同一项目但位于不序包中的两个model类。
- 为了简化跨平台架构的使用,因为命名约定不同。
- 要使用比Realm强制使用的57个字符的限制长的Java类名。
- 在Java中更改字段名称而不会强制应用程序用户完成迁移过程。
在这些情况下,可以使用@RealmModule,@RealmClass
或@RealmField
注解定义其他名称,以覆盖内部使用的名称。
您可以在module定义命名策略,这将影响module的所有类部分:
@RealmModule(
allClasses = true,
classNamingPolicy = RealmNamingPolicy.LOWER_CASE_WITH_UNDERSCORES,
fieldNamingPolicy = RealmNamingPolicy.LOWER_CASE_WITH_UNDERSCORES
)
public class MyModule {
}
您可以为该类定义自定义名称,或者可以定义将影响该类中所有字段的字段命名策略。 这将覆盖所有module级别的设置:
@RealmClass(name = "__Person", fieldNamingPolicy = RealmNamingPolicy.PASCAL_CASE)
public class Person extends RealmObject {
public String name;
}
您可以为字段定义自定义名称,这将覆盖所有Class类和Module模块级别的设置:
public class extends RealmObject {
@RealmField(name = "person_name")
public String name;
}
选择与Java模型类中使用的名称不同的内部名称具有以下含义:
- DynamicRealm上的查询必须使用内部名称。 普通Realm实例上的查询必须继续使用Java类中定义的名称。
- 创建类和字段时,迁移必须使用内部名称。
- 报告的架构错误将使用内部名称。
请注意,更改内部名称不会影响从JSON导入数据。 JSON数据仍必须遵循Realm Java类中定义的名称。
在使用Moshi,GSON或Jackson之类的标准库解析JSON时,请务必记住这些库定义了从JSON到Java的转换,同时设置了内部Realm名称也定义了从Java到Realm文件的转换。这意味着如果您想使用这些库将数据从JSON导入Realm,则仍然需要提供JSON解析器库和Realm的注释。
使用Moshi,它看起来像这样:
public class Person extends RealmObject {
@Json(name = "first_name") // JSON输入中使用的名称。
@RealmField(name = "first_name") // Realm文件内部使用的名称。
public string firstName; // Java中使用的名称
}
有关更多信息,请参见RealmNamingPolicy。