一、为什么选择 Realm?
- 无需 SQL,直接用对象操作数据
- 读写性能高,支持实时数据响应
- 自带数据监听,数据变化 UI 自动刷新
- 支持增量同步 / 增量下载,完美适配移动端离线业务
- 跨平台(iOS/Android/React Native)一套代码通用
二、环境搭建
安装依赖 * Android 12+ / RN 0.71.3 / Realm 11.10.1
# React Native 项目
npm install realm @realm/react
三、操作案例:
需求:
仓库作业系统,离线操作,
物料辅计量单位等基础信息内容存储在本地,
页面中操作查询的时候查询本地基础数据支持离线操作
1. 定义模型: 物料档案、计量单位等
import Realm from 'realm';
// 实体模型
/**
* 物料档案(MATERIAL)结构化存储
* - primaryKey: code
* 目标:可通过 code 快速取到 wholemanaflag / qualityunit 等字段
*/
export class Material extends Realm.Object<Material> {
code!: string;
pk_group!: string;
pk_org!: string;
pk_material!: string;
pk_marbasclass!: string;
name!: string;
materialshortname!: string;
materialtype!: string;
materialbarcode!: string;
materialspec!: string;
graphid!: string;
pk_measdoc!: string;
pk_marasstframe!: string;
wholemanaflag!: string;
serialmanaflag!: string;
islinecontrol!: string;
sernumunit!: string;
qualitymanflag!: string;
qualitynum!: string;
qualityunit!: string;
version!: string;
dr!: string;
irownum!: string;
def20!: string;
def21!: string;
def50!: string;
bcolltype_1!: string;
bcolltype_2!: string;
bcolltype_3!: string;
bcolltype_4!: string;
bcolltype_5!: string;
updatedAt!: Date;
static schema: Realm.ObjectSchema = {
name: 'Material',
primaryKey: 'code',
properties: {
code: 'string',
pk_group: 'string',
pk_org: 'string',
pk_material: 'string',
pk_marbasclass: 'string',
name: 'string',
materialshortname: 'string',
materialtype: 'string',
materialbarcode: 'string',
materialspec: 'string',
graphid: 'string',
pk_measdoc: 'string',
pk_marasstframe: 'string',
wholemanaflag: 'string',
serialmanaflag: 'string',
islinecontrol: 'string',
sernumunit: 'string',
qualitymanflag: 'string',
qualitynum: 'string',
qualityunit: 'string',
version: 'string',
dr: 'string',
irownum: 'string',
def20: 'string',
def21: 'string',
def50: 'string',
bcolltype_1: 'string',
bcolltype_2: 'string',
bcolltype_3: 'string',
bcolltype_4: 'string',
bcolltype_5: 'string',
updatedAt: 'date'
}
};
}
/**
* 计量单位(MEASDOC)结构化存储
* - primaryKey: pk_measdoc
* 目标:
* - 可通过 pk_measdoc 直接取 name / code / bitnumber 等字段
* - 也允许通过 code 过滤查询到单位信息
*/
export class MeasDoc extends Realm.Object<MeasDoc> {
pk_measdoc!: string;
code!: string;
name!: string;
pk_group!: string;
pk_org!: string;
dr!: string;
bitnumber!: string;
irownum!: string;
bcolltype_1!: string;
bcolltype_2!: string;
bcolltype_3!: string;
bcolltype_4!: string;
bcolltype_5!: string;
updatedAt!: Date;
static schema: Realm.ObjectSchema = {
name: 'MeasDoc',
primaryKey: 'pk_measdoc',
properties: {
pk_measdoc: 'string',
code: 'string',
name: 'string',
pk_group: 'string',
pk_org: 'string',
dr: 'string',
bitnumber: 'string',
irownum: 'string',
bcolltype_1: 'string',
bcolltype_2: 'string',
bcolltype_3: 'string',
bcolltype_4: 'string',
bcolltype_5: 'string',
updatedAt: 'date'
}
};
}
2.增量下载逻辑:
只拉取本地「最后更新时间」之后的新数据 / 变更数据,节省流量和性能。
javascript
//下载下来数据allRows 下载时间 storedAt
const r = upsertMaterial(realm, allRows, storedAt);
javascript
/**
* 写入 MATERIAL(结构化 upsert)
* - 适合增量下载:只需要把本次返回的 rows upsert 进去即可
*/
export function upsertMaterial(
realm: Realm,
rows: any[],
storedAt: Date
): { count: number; lastTime: string } {
const updateMode: any = (Realm as any).UpdateMode?.Modified ?? 'modified';
const safe = (v: any) => String(v ?? '');
const list = Array.isArray(rows) ? rows : [];
realm.write(() => {
for (const r of list) {
const code = safe(r?.code).trim();
if (!code) continue;
realm.create(
'Material',
{
code,
pk_group: safe(r?.pk_group),
pk_org: safe(r?.pk_org),
pk_material: safe(r?.pk_material),
pk_marbasclass: safe(r?.pk_marbasclass),
name: safe(r?.name),
materialshortname: safe(r?.materialshortname),
materialtype: safe(r?.materialtype),
materialbarcode: safe(r?.materialbarcode),
materialspec: safe(r?.materialspec),
graphid: safe(r?.graphid),
pk_measdoc: safe(r?.pk_measdoc),
pk_marasstframe: safe(r?.pk_marasstframe),
wholemanaflag: safe(r?.wholemanaflag),
serialmanaflag: safe(r?.serialmanaflag),
islinecontrol: safe(r?.islinecontrol),
sernumunit: safe(r?.sernumunit),
qualitymanflag: safe(r?.qualitymanflag),
qualitynum: safe(r?.qualitynum),
qualityunit: safe(r?.qualityunit),
version: safe(r?.version),
dr: safe(r?.dr),
irownum: safe(r?.irownum),
def20: safe(r?.def20),
def21: safe(r?.def21),
def50: safe(r?.def50),
bcolltype_1: safe(r?.bcolltype_1),
bcolltype_2: safe(r?.bcolltype_2),
bcolltype_3: safe(r?.bcolltype_3),
bcolltype_4: safe(r?.bcolltype_4),
bcolltype_5: safe(r?.bcolltype_5),
updatedAt: storedAt
},
updateMode
);
}
const total = realm.objects<Material>('Material').length;
upsertMeta(realm, 'MATERIAL', total, storedAt);
});
const meta = realm.objectForPrimaryKey<BaseDataMeta>('BaseDataMeta', 'MATERIAL');
return {
count: meta?.rowCount ?? realm.objects<Material>('Material').length ?? 0,
lastTime: toTimeString(meta?.lastStoredAt ?? storedAt)
};
}
realm.create()第三个参数是 mode(写入模式),用来控制当数据主键已存在时,应该怎么处理。
3.模式 Realm 提供 3 种模式:
1. Realm.UpdateMode.Never(默认)
- 含义:不更新,只新增
- 行为 :如果主键已存在,直接报错
2. Realm.UpdateMode.Modified(最常用!)
- 含义 :存在则更新,不存在则新增(upsert)
- 行为 :根据主键匹配
- 有这条数据 → 只更新变化的字段
- 没有这条数据 → 直接新增
3. Realm.UpdateMode.All
- 含义:全量覆盖
- 行为 :如果数据存在,直接用新对象覆盖整个对象
所有 写操作(增 / 删 / 改) 必须放在
realm.write(() => { ... })里面单条操作靠 主键定位
四、常用操作:
1.查询单条:
javascript
const item = realm.objectForPrimaryKey('Material', code);
2. 新增单条
javascript
// 新增
realm.write(() => {
realm.create('Material', {
id: Date.now(), // 唯一主键
name: '原料仓库', // 字段
address: '上海',
stock: 100,
updateTime: new Date()
});
});
3. 修改单条(最常用)
javascript
realm.write(() => {
// 1. 找到要修改的那一条
const item = realm.objectForPrimaryKey('Material', 123);
if (item) {
// 2. 直接改字段
item.name = '修改后的仓库名';
item.stock = 200;
item.updateTime = new Date();
}
});
realm.write(() => {
realm.create(
'Material',
{
id: 123, // 必须传主键
name: '新名称',
stock: 200
},
Realm.UpdateMode.Modified // 有则更新,无则新增
);
});
4. 删除单条
javascript
realm.write(() => {
// 1. 找到要删的那一条
const item = realm.objectForPrimaryKey('Material', 123);
if (item) {
// 2. 删除
realm.delete(item);
}
});