`
iaiai
  • 浏览: 2146482 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

为什么我不再使用Realm

 
阅读更多
也许你并没有听说过 Realm ,这是一个面向安卓(亦面相iOS)的移动端数据库技术。和SQLite不同,它允许你在持久层直接和数据对象工作。在它之上是一个函数式风格的查询api,众多的努力让它比传统的SQLite 操作更快 。基于这些原因让我决定试试Realm 。

blob.png

大约一年前,当我第一次使用Realm 的时候,给我的第一印象非常不错。我需要保持一些用户数据在手机本地,但是SharedPreferences用起来有点复杂了。Realm允许我用快速干净的代码里完成这件事情。它完全不需要像SQLite那样自己手动写额外的代码。

我接下来的一个项目在缺少网络连接的时候需要一个比较复杂的离线模式。从网络抓取的数据必须保存在手机本地。我决定完全使用Realm 并观察它随项目增大是如何扩大的。

而我很快发现Realm让数据模型的工作成了一种负担。它有几个限制以至于我必须在整个代码基础上做处理。结果我尝试在Realm之上抽象出另外一层来减轻这种限制。

定义对象
为了说明这些限制,让我们从简单的Person对象开始:
public class Person extends RealmObject {
  private String name;
  private int age;
   
  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; }
}

注意我们必须直接继承自RealmObject。这阻碍我们利用数据模型中的任意类型的继承。

并且我们还不能定义除setters 和 getters之外的实例方法。如果你想重写equals 或者toString`那么你就别想了。这样导致的另外一个后果就是我们只能局限于使用标记接口模式(marker interfaces) (注解也是可以的 )。

不仅仅被限制于setters 和 getters,实际上我们还必须提供它们。因此我们的数据对象是不可变的!另外,setters 和 getters方法只是为Realm替换自己实现的代理方法。它不能操作数据,跑出异常,或者打印日志。

虽然我们可以提供一个非默认的构造函数,但是我们必须保证存在一个空的构造函数。如果你想用一个builder 或者工厂方法来作为实例化的唯一途径,那么这种限制就成了一个问题。稍后我们将看看如何用Realm创建对象。

在我们能持有的field类型方面,也有一些限制。所有的基本数据类型以及它们的封装类型都能支持,包括String, Date, 和byte[]`。但是对于其它类型,为了被持久化,必须继承自RealmObject。Lists可以用RealmList来支持。

但是也仅此而已。如果我们想使用枚举而不是int,是没有办法的(找到一个使用@IntDef的理由了)。我们还不能使用集合类型,比如Set和Map。

创建和更新对象
为了创建一个Person类的实例,我们必须做如下事情:
Realm realm = Realm.getInstance(context);
realm.beginTransaction();
Person person = realm.createObject(Person.class);
person.setName("John");
person.setAge(25);
realm.commitTransaction();

你会注意到我们必须包裹一下Person 对象,同时任何对它的修改都在一个transaction 中。如果我们能在transaction 之外做这件事情并在我们准备好的时候持久化它,就要灵活得多。而现在我们在想要创建或者更新我们对象的任何时候都要卡在写额外的Realm 代码上面。

之前我提过我们可以定义一个非默认的构造函数。比如,对于Person我们可能有一个带有name 和 age的构造函数:
public class Person extends RealmObject {
  private String name;
  private int age;
   
  public Person(String name, int age) {
    this.name = name;
    this.age = age;
  }
   
  public Person() {
    // required empty public constructor
  }
   
  // setters and getters
  ...
}

我们不再需要直接调用setters :
Person person = new Person("John", 25);
realm.beginTransaction();
Person realmPerson = realm.copyToRealm(person);
realm.commitTransaction();

这让我们省去了一些写额外代码的时间,但是仍然受限于transaction。

Mitigating These Issues
为了避免在基础代码中处理这些限制,我为数据对象定义了两套类: POJOs (普通对象)和Realm 对象。然后我们创建了一个能在两者之间映射的abstraction 。

这是可行的,但是有两个主要的问题。第一个是当你持有许多不同类型的对象时,你需要许多代码来映射这些类。管理这些是很痛苦的而且这也很容易产生bug。 对象映射的概念以及它存在的问题都不是什么新东西了。

第二个就是我觉得这有违最初使用Realm的目的。能在持久层直接使用对象是它的主要好处。如果我们为了使用POJO而必须在Realm 之上创建抽象,那么它相比SQLite或者像 DBFlow一样的ORM的优势在哪里呢?

值得一提的是Realm 的维护者已经 意识到了这些限制 ,而且在一定程度上,许多问题都可能被解决(见这里 和 这里))。Realm也的确具有一些其它的优势,比如性能以及在iOS和安卓之间共享数据的能力。
分享到:
评论

相关推荐

    Realm-JSON, 使用领域和JSON的简洁的地幔.zip

    Realm-JSON, 使用领域和JSON的简洁的地幔 Realm JSON 一种简洁的地幔使用领域和JSON的方法...更改方法 - deepCopy 替换了 - shallowCopy 以前的功能,它不再维护对象键的一个主更新为使用领域 0.85.0中的原生主键支持更

    realm-tutorial:MongoDB领域教程

    :warning: 不推荐使用该存储库不再维护。 请按照上的教程进行操作请参阅以下特定客户回购协议: 等等。 原始自述文件在下面继续。任务跟踪器教程任务跟踪器是一个协作项目管理工具。应用说明移动应用程序(Swift / ...

    realm-0.86.1

    realm-0.86.1版本。Realm支持Eclipse的最后版本是0.87.5,更新的版本只支持AndroidStudio,不再支持Eclipse了,所以这里是0.86.1的资源。

    ZeroKit-Realm-auth-provider:用于Realm Object Server的身份验证模块,以启用ZeroKit身份验证

    注意:该项目已终止,不再由Tresorit维护或支持。 该存储库仅用于存档目的。ZeroKit-Realm-Auth-Provider ZeroKit-Realm-auth-provider是Realm Object Server(ROS)的身份验证模块,用于启用基于ZeroKit的身份验证...

    realm-tasks:受Real启发,由Realm构建的To Do应用

    领域任务(已弃用) 该项目已弃用,不再有效维护。 一个基本的任务管理应用程序...1.获取领域对象服务器Realm Tasks应用程序使用Realm对象服务器在它们之间同步任务。 访问Realm对象服务器的最快方法是注册免费的Realm

    rollup-plugin-realm-uri:回到我的废话

    该插件增加了对使用realm:方案URI的ES导入说明符的支持,以允许导入对当前领域内的全局值进行重复数据删除的固定引用。 变化 2.0.0: Meta:不再在dist中生成CJS入口点 Meta:现在导出esbuild()适配器函数 错误...

    Realm Royale Wallpapers & New Tab-crx插件

    安装Realm Royale高清壁纸New Tab主题,并享受Realm Royale世界,皮肤,故事模式等的高清壁纸。 爱情王国皇家吗? 安装Realm Royale HD Wallpapers New Tab Theme,并享受Realm Royale Story模式,游戏玩法,皮肤,...

    RealmEasy:过时

    为什么是 RealmEasy? 我创建 RealmEasy 来解决两个问题。 从 Realm 0.87 开始,不再可能将默认 Realm 设置为 inMemoryRealm。 这意味着您必须要么使用真正的 default.realm 进行单元测试,要么在整个代码中传递该...

    ZeroKit-NodeJs-backend-sample-realm:一个可重用的示例快递应用程序,设计为使用脱机领域作为数据库的网站和移动示例的后端

    注意:该项目已终止,不再由Tresorit维护或支持。 该存储库仅用于存档目的。 ZeroKit Node示例后端 这是一个使用应用程序开发自己的ZeroKit的后端服务时可以参考的示例。 它提供了一个功能齐全的REST api,供我们...

    shield-custom-realm-example

    因此,我们不再维护此样本领域存储库。 如果您希望查看示例领域,则可以看到一个有效的,维护的 博客文章还提供了一个示例,该示例在Elasticsearch 6.3或更高版本中实现自定义领域,并提供了一些帮助。 Elastic...

    基于SpringBoot+Shiro+Redis+Jwt+Thymeleaf+MyBatis 开发的后台用户、角色+源代码+文档

    * 更改后台登录为单realm,不再支持多realm * 优化日期时间工具类,使用Instant、LocalDateTime、LocalDate实现线性安全 * 修复Java开发规约中级警告及部分低级警告 * 增加debug日志输出开关 ###更新日期2018-12-28...

    -deprecated-Herald_iOS_v2:小猴偷米 iOS客户端v2 试验品

    不再使用UserDefault作为缓存容器,暂定使用YYCache和Realm,协同内存缓存与磁盘缓存。 目前进度 1.业务逻辑层 首页网络请求与缓存逻辑 信息板 登录模块 活动模块 课表模块 通知模块 跑操与体侧模块 一卡通...

    kong-plugin-jwt-keycloak:验证Keycloak发出的访问令牌的插件

    Kong插件jwt-keycloak 注意:我将不再维护此插件。 感谢您对此项目的所有积极反馈和关注。 随意分叉并保持活动。 干杯! 插件,用于验证发出的访问令牌。 它使用提供从特定于每个端点允许的发行者加载公共密钥。 该...

Global site tag (gtag.js) - Google Analytics