初窥Realm数据库(二)

作者: NiubilityLeo | 来源:发表于2016-05-19 15:25 被阅读854次

前言

下面是我对realm研究的第一篇文章的传送门:初窥Realm数据库。这篇文章主要是对之前一篇的补充,会对realm做更深一步的探讨。我会根据realm的一些特性展开介绍。

事务

realm对数据的操作都是基于事务的。首先介绍一下什么是事务:事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。我认为最重要的属性是原子性,这保证了线程安全,同时在一个事务中的诸多操作,只要一个不成功,其他皆不成功。这样可以尽力保证我们的数据是干净的。
realm提供了两种构建事务的方法:

    [realm beginWriteTransaction];
    //你的操作
    [realm addObject:province];
    [realm commitWriteTransaction];

基于block的构建方法:

[[RLMRealm defaultRealm] transactionWithBlock:^{
        //你的操作
        [[RLMRealm defaultRealm] addObject:province];
    }];

这两种方式的效果是一模一样的,也就是说block构建方式也是同步的,点进去看一下源码:

- (BOOL)transactionWithBlock:(void(^)(void))block error:(NSError **)outError {
    [self beginWriteTransaction];
    block();
    if (_realm->is_in_transaction()) {
        return [self commitWriteTransaction:outError];
    }
    return YES;
}

这样看出block只是起到了一个代码块的作用。这个在官网文档中也有提及。

realm的正确用法

从刚才的源码看出,每次你开启一个事务,realm会做出两件事,一个是开启写入的权限,然后提交你的事务。一个事务的处理需要的开销其实是比较大的。一些连续的操作应该尽量放在一个事务中去处理。

错误的用法:

for(int i=0;i<array.count;i++)
    {
        ProvinceEntity *province = [pDic objectForKey:array[i]];
        [[RLMRealm defaultRealm] transactionWithBlock:^{
            [[RLMRealm defaultRealm] addObject:province];
        }];
    }

正确的用法:

[[RLMRealm defaultRealm] transactionWithBlock:^{
        for(int i=0;i<array.count;i++)
        {
            ProvinceEntity *province = [pDic objectForKey:array[i]];
            [[RLMRealm defaultRealm] addObject:province];
        }
    }];

RLMResults自动更新:

RLMResults是底层数据的动态表现,其会进行自动更新,这意味着检索到的结果不能进行重复检索。它们会反映出当前线程上 Realm 的当前状态,包括在当前线程上的写事务当中:

RLMResults<Dog *> *puppies = [Dog objectsInRealm:realm where:@"age < 2"];
puppies.count; // => 0
[realm transactionWithBlock:^{ [Dog createInRealm:realm withValue:@{@"name": @"大黄", @"age": @1}];}];
puppies.count; // => 1

根据这个特性,realm提供了对数据监听的一些接口,这样数据一旦发生变化,就能进行ui的更新,非常的方便。这也是realm的强大之处。

realm数据库迁移

对于移动端数据库来说最头疼的就是数据库版本的迁移了。一张表中字段的新增,更新,删除,都会影响上个版本的用户,如果不做迁移,升级以后就直接crash了。回想一下coredata的迁移,假如你新增了表或者是新增了字段,那就要做新的版本的去迁移。步骤也是很麻烦的,还要重新生成文件。如果你表中字段发生变化了,那就麻烦了,要做map。
realm的数据库容错性还是不错的:

  • 1.新增删除表,不需要做迁移
  • 2.新增删除字段不需要做迁移。Realm 会自行检测新增和需要移除的属性,然后自动更新硬盘上的数据库架构。

realm比较厉害的一点是,他不光能map字段,还能根据你的需要去匹配。接下来是例子:

RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.schemaVersion = 2;
config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) 
{ 
// enumerateObjects:block: 遍历了存储在 Realm 文件中的每一个“Person”对象 
  [migration enumerateObjects:Person.className block:^(RLMObject *oldObject, RLMObject *newObject) { 
// 只有当 Realm 数据库的架构版本为 0 的时候,才添加 “fullName” 属性 
    if (oldSchemaVersion < 1) {
     newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@", oldObject[@"firstName"], oldObject[@"lastName"]];
     } 
// 只有当 Realm 数据库的架构版本为 0 或者 1 的时候,才添加“email”属性
     if (oldSchemaVersion < 2) { 
    newObject[@"email"] = @""; 
    } 
  }];
};
[RLMRealmConfiguration setDefaultConfiguration:config];
// 现在我们已经成功更新了架构版本并且提供了迁移闭包,打开旧有的 Realm 数据库会自动执行此数据迁移,然后成功进行访问
[RLMRealm defaultRealm];

总结

realm日常需要用到的方法和一些注意点差不多就这些了,掌握这些对于日常的开发不成问题。这也体现出了realm学习成本并不高,后面我会封装一些比较常用的方法出来,放在github上供大家使用。如果你对realm有什么疑问或者见解,欢迎给我留言。

下面是我封装的一个helper,主要是对更新和删除进行了封装,使用起来更加的简单传送门:RealmHelper

感谢

官网:https://realm.io/

相关文章

网友评论

    本文标题:初窥Realm数据库(二)

    本文链接:https://www.haomeiwen.com/subject/mdlgrttx.html