移动数据库 Realm 在 React-Native 的使用详解

在开发中有些数据咱们须要在本地进行持久化存储,在须要的地方调用。通常来讲,咱们会用到 AsyncStorage 来对数据进行持久化的存储,这是官方推荐使用的存储方式,相似于 iOS 中的 NSUserDefault ,区别在于,AsyncStorage 只能存储字符串键值对,而 NSUserDefault 能够存储字符串和 number。如此,当咱们须要存储的数据规模较为庞大时,须要考虑选择另外一种持久化的存储方式-- Realmjavascript

Realm:与 SQList 进行数据存储相比,在性能上,各有优点,可是操做上,Realm 有明显优点,也更方便使用。其中囊括了各端的使用,包括java

接下来咱们就来看看怎么使用 Realmnode

1.安装

npm install --save realmreact

2.连接

react-native link realmlinux

须要注意有两点:android

1.安卓端可能使用 link 无效,这时能够进行如下步骤:

  • android/settings.gradle 内添加:
include ':realm'
project(':realm').projectDir = new File(rootProject.projectDir, '../node_modules/realm/android')
复制代码
  • android/app/build.gradle 增长依赖库:
// When using Android Gradle plugin 3.0 or higher
dependencies {
  implementation project(':realm')
}

// When using Android Gradle plugin lower than 3.0
dependencies {
  compile project(':realm')
}
复制代码
  • MainApplication.java 中导入而且连接 package:
import io.realm.react.RealmReactPackage; // add this 

import public class MainApplication extends Application implements ReactApplication {
    @Override
    protected List<ReactPackage> getPackages() {
        return Arrays.<ReactPackage>asList(
            new MainReactPackage(),
            new RealmReactPackage() // add this line
        );
    }
}
复制代码

2.由于我是在0.56版本上开大,所以须要固定选择安装的版本为 2.16.0,记住把2上面的 ^ 去掉。

3.初步使用:

Realm.open({
      schema: [{name: 'Dog', properties: {name: 'string'}}]
    }).then(realm => {
      realm.write(() => {
        realm.create('Dog', {name: 'Rex'});
      });
      this.setState({ realm });
    });
复制代码

4.介绍:

Realm JavaScript enables you to efficiently write your app’s model layer in a safe, persisted and fast way. It’s designed to work with React Native数据库

意思是在 RN 上用很快,很安全,很棒棒的。npm

来看一个例子:swift

//在文件中引入 realm
const Realm = require('realm');

// 建立数据模型,而且在 properties 中建立属性
const CarSchema = {
  name: 'Car',
  properties: {
    make:  'string',
    model: 'string',
    miles: {type: 'int', default: 0},
  }
};
const PersonSchema = {
  name: 'Person',
  properties: {
    name:     'string',
    birthday: 'date',
    cars:     'Car[]',
    picture:  'data?' // optional property
  }
};

//realm 使用的特别之处,把建立的数据模型整合到 schema  之中,经过 open 方法打开一条 Realm
Realm.open({schema: [CarSchema, PersonSchema]})
  .then(realm => {
    // 只能在 write 方法中操做数据,查询则不用
    realm.write(() => {
    //create 建立数据的方法
      const myCar = realm.create('Car', {
        make: 'Honda',
        model: 'Civic',
        miles: 1000,
      });
      // 更新数据
      myCar.miles += 20; 
    });

    // 查询,返回数组
    const cars = realm.objects('Car').filtered('miles > 1000');
    
    //这个时候长度是1
	cars.length // => 1

    // 再次新增另外一条数据
    realm.write(() => {
      const myCar = realm.create('Car', {
        make: 'Ford',
        model: 'Focus',
        miles: 2000,
      });
    });

    // 查询结果更新,变成2
    cars.length // => 2
  })
  .catch(error => {
    console.log(error);
  });
复制代码

4.Realm 独有的管理工具--> Realm Studio

用于查看存储在本地的数据react-native

MacLinuxWindows 版本

5.详解

Realm.open({schema: [Car, Person]})
  .then(realm => {
    // ...use the realm instance here
  })
  .catch(error => {
    // Handle the error here if something went wrong
  });
复制代码

open 方法是打开数据库的方法, open(config: Realm.Configuration): ProgressPromise;,

还有一个是异步线程上的使用:static openAsync(config: Realm.Configuration, callback: (error: any, realm: Realm) => void, progressCallback?: Realm.Sync.ProgressNotificationCallback): void

Configuration 里带有不少参数,咱们进去看看:

interface Configuration {
        encryptionKey?: ArrayBuffer | ArrayBufferView | Int8Array;
        migration?: (oldRealm: Realm, newRealm: Realm) => void;
        shouldCompactOnLaunch?: (totalBytes: number, usedBytes: number) => boolean;
        path?: string;
        readOnly?: boolean;
        inMemory?: boolean;
        schema?: (ObjectClass | ObjectSchema)[];
        schemaVersion?: number;
        sync?: Partial<Realm.Sync.SyncConfiguration>;
        deleteRealmIfMigrationNeeded?: boolean;
        disableFormatUpgrade?: boolean;
}
复制代码

着重讲几个参数:

  • path:建立一个指定存储路径的 Realm,默认是 Realm.realm,也能够本身命名
  • migration:移动功能,把数据迁移到另外一个地方
  • sync:一个同步对象,在数据库服务中打开 Realm 的同步
  • inMemoryRealm 将在内存中打开,而且对象不会被持久化; 一旦最后一个 Realm 实例关闭,全部对象都会消失
  • deleteRealmIfMigrationNeeded:若是处于开发模式,可使用这项功能来自动删除数据
  • schemaVersion
    • 若是表格中新增的字段,而后不作任何变化的打开,则程序就会报错;系统默认打开的版本是0,为了不程序报错,也为了能正确的更新表格数据,应该这样写:Realm.open({schema: [Car, Person], schemaVersion: 1});
    • 查看当前版本:Realm.schemaVersion(Realm.defaultPath);

6.数据模型

当初始化的时候,经过建立的 Realm,数据模型伴随着 schema 的生成而建立,每一个 schema 包含 name(模型名称),primaryKey(惟一标志符,一般用于数组),properties(属性)

const CarSchema = {
  name: 'Car',
  properties: {
    make:  'string',
    model: 'string',
    miles: {type: 'int', default: 0},
  }
};
const PersonSchema = {
  name: 'Person',
  properties: {
    name:     'string',
    birthday: 'date',
    cars:     'Car[]'
    picture:  'data?', // optional property
  }
};

// Initialize a Realm with Car and Person models
Realm.open({schema: [CarSchema, PersonSchema]})
  .then(realm => {
    // ... use the realm instance to read and modify data
  })
复制代码

7.参数类型

参数类型有7种,bool,int,float,double,string,data,date

注意的点

  • 其中 dataArrayBuffer,具体是什么我还不太清楚,不过这个并非数组的意思。
  • 必填属性保存的时候不支持 null 或者 undefined,选填属性能够保存这两种类型的值,所以若是在赋值时有可能属于这些值时,应该先作好判断,不然会抛出异常
  • 选填属性optional 或者在类型后给个 ? 来作表示,好比:
const PersonSchema = {
  name: 'Person',
  properties: {
    realName:    'string', // 必填属性
    displayName: 'string?', // 选填属性
    birthday:    {type: 'date', optional: true}, // 选填属性
  }
};
复制代码
  • 除了存储单个值以外,还能够将属性声明为任何受支持的基本类型的列表。例如存储相似 JavaScript array 的话,经过将[]附加到类型名称来完成
const PersonSchema = {
  name: 'Person',
  properties: {
    name: 'string',
    testScores: 'double?[]'
  }
};

let realm = new Realm({schema: [PersonSchema, CarSchema]});

realm.write(() => {
  let charlie = realm.create('Person', {
    name: 'Charlie',
    testScores: [100.0]
  });

  
  charlie.testScores.push(null);

  
  charlie.testScores.push(70.0);
  
  console.log('charlie.testScores==',charlie.testScores)//打印结果:{ '0': 100, '1': null, '2': 70 }
});
复制代码
  • 另外,若是须要建立一个属性中包含多种对象的数组,那能够往属性种添加 schema

8.数据操做

  • 更新数据须要在 write 方法内写,查询数据则不用,而且最好使用 try/catch 方式以获取抛出的异常:
try {
  realm.write(() => {
    realm.create('Car', {make: 'Honda', model: 'Accord', drive: 'awd'});
  });
} catch (e) {
  console.log("Error on creation");
}
复制代码
  • 删除对象:
realm.write(() => {
  // Create a book object
  let book = realm.create('Book', {id: 1, title: 'Recipes', price: 35});

  // Delete the book
  realm.delete(book);

  // Delete multiple books by passing in a `Results`, `List`,
  // or JavaScript `Array`
  let allBooks = realm.objects('Book');
  realm.delete(allBooks); // Deletes all books
});
复制代码
  • filtered 查询数据的时候,参数只能传常量或者属性名称(目前没找到传变量的方法,因此这个方法不是很灵活
  • 更新数据除了使用 filtered,还可使用建立的方法,只要在后面把默认修改状态改成 true
realm.create('dtList'{realmId :realmId,editDataType:'DELETE'},true);
复制代码

须要注意的还有一点:

根据文档上的解释:

If your model class includes a primary key, you can have Realm intelligently update or add objects based off of their primary key values. This is done by passing true as the third argument to the create method:

须要设置 primary key,这个一开始我觉得是随便填,原来用处是在这里,这个 primary key 是跟 properties 内的一个参数相关联,所以须要设置一个相似 id 的主键,以此来作修改指定数据的依据。

除了用 id 作主键,若是存储的数据大,而且还涉及到与后台的信息同步,那就能够用生成随机 UDID 的方法:

export function  getUUID(){
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            var r = Math.random() * 16 | 0,
            v = c == 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
 		}).toUpperCase();
}
复制代码

这样在建立数据或者修改的时候就不会出现涉及到被覆盖的数据。

在结束操做的时候,须要执行关闭数据库操做的处理,这样避免 realm 一直占用线程资源,程序发生奔溃现象。

realm.close()

相关文章
相关标签/搜索