Realm 是一个什么样的数据库?

ily*_*lya 2 database realm ios

Realm是一个什么样的数据库?是ORM吗?或者它像对象数据库一样工作吗?也许数据库结构会以某种方式影响设计过程?Realm 数据库的设计有什么细微差别吗?

我在这里问,因为我在官方网站上没有找到任何答案

Epi*_*rce 5

不幸的是,我实际上并没有使用iOS版本,但我确实使用 Android 版本,它的功能集与 iOS 版本越来越相似,并且它们共享相同的功能core,并且更接近于提供相同的功能通过 统一行为object-store

因此,这个答案的大部分内容将基于 Swift API 文档。(领域 Swift 2.6.1)


Realm 默认是一个对象存储。从技术上讲,它将您的数据存储在模式中,其中模式由类定义,例如

// from https://realm.io/docs/swift/latest/#models
class Person: Object {
    dynamic var name = ""
    dynamic var birthdate = NSDate(timeIntervalSince1970: 1)
    let dogs = List<Dog>()
}
Run Code Online (Sandbox Code Playgroud)

Realm 的有趣之处在于它不是一个关系数据库;而是一个数据库。它直接存储对象。事实上,Realm 管理的对象(也称为通过查询 Realm 获得的对象,或者由 Realm 创建的新对象)直接映射到底层 Realm 文件,并且不将数据复制到字段,访问器直接读取和写入领域文件。

这种“直接访问”导致所有数据仅在访问时才加载(惰性求值),因此不需要缓存托管对象(!)。

所有写入都是事务性的。在事务之外,无法修改托管 RealmObject。


在你的对象之间,你可以有关系(链接):

// from https://realm.io/docs/swift/latest/#relationships
class Dog: Object {
    // ... other property declarations
    dynamic var owner: Person? // to-one relationships must be optional
}

class Person: Object {
    // ... other property declarations
    let dogs = List<Dog>() // to-many relationship
}
Run Code Online (Sandbox Code Playgroud)

任何关系(一对一、对多)都有其对应的backlink,您可以将其定义为“链接到该对象的对象”。

// from https://realm.io/docs/swift/latest/#relationships
class Dog: Object {
    dynamic var name = ""
    dynamic var age = 0
    let owners = LinkingObjects(fromType: Person.self, property: "dogs")
}
Run Code Online (Sandbox Code Playgroud)

Realm 的托管对象是“实时、不可变的数据视图”(来自此处),它们会就地发生变化,并且您可以通过notification token(来自此处)收到有关它的更改通知。这同样适用于任何托管 RealmObject,也适用于查询结果

这意味着,查询结果会自动异步计算,并且只有在给定索引处访问的元素才会以延迟加载的方式从数据库中读取!因此,不需要分页。

任何线程上的任何写入都会自动向与运行循环关联的线程发送通知,并且查询结果会自动更新,并调用更改侦听器(通知块)。

// from https://realm.io/docs/swift/latest/#collection-notifications
  override func viewDidLoad() {
    super.viewDidLoad()
    let realm = try! Realm()
    let results = realm.objects(Person.self).filter("age > 5")

    // Observe Results Notifications
    notificationToken = results.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in
      guard let tableView = self?.tableView else { return }
      switch changes {
      case .initial:
        // Results are now populated and can be accessed without blocking the UI
        tableView.reloadData()
        break
      case .update(_, let deletions, let insertions, let modifications):
        // Query results have changed, so apply them to the UITableView
        tableView.beginUpdates()
        tableView.insertRows(at: insertions.map({ IndexPath(row: $0, section: 0) }),
                           with: .automatic)
        tableView.deleteRows(at: deletions.map({ IndexPath(row: $0, section: 0)}),
                           with: .automatic)
        tableView.reloadRows(at: modifications.map({ IndexPath(row: $0, section: 0) }),
                           with: .automatic)
        tableView.endUpdates()
        break
      case .error(let error):
        // An error occurred while opening the Realm file on the background worker thread
        fatalError("\(error)")
        break
      }
    }
  }

  deinit {
    notificationToken?.stop()
  }
Run Code Online (Sandbox Code Playgroud)

最广为人知的限制是 RealmObjects、RealmResults 和 Realms不能在线程之间传递。(其他限制见此处)。

给定线程上的 RealmObject/RealmResults/Realm 只能在打开其相应 Realm 实例的线程上访问(请阅读此处)。(例外是使用在线程之间发送的 RealmObject ThreadSafeReference,请参见 此处)。

因此,后台线程需要自己的 Realm 实例,通常包装在一个 中autoreleasepool,请参见此处

// from https://realm.io/docs/swift/latest/#using-a-realm-across-threads
DispatchQueue(label: "background").async {
  autoreleasepool {
    // Get realm and table instances for this thread
    let realm = try! Realm()

    // Break up the writing blocks into smaller portions
    // by starting a new transaction
    for idx1 in 0..<1000 {
      realm.beginWrite()

      // Add row via dictionary. Property order is ignored.
      for idx2 in 0..<1000 {
        realm.create(Person.self, value: [
          "name": "\(idx1)",
          "birthdate": Date(timeIntervalSince1970: TimeInterval(idx2))
        ])
      }

      // Commit the write transaction
      // to make this data available to other threads
      try! realm.commitWrite()
    }
  }
}
Run Code Online (Sandbox Code Playgroud)