Realm使用入门 (一)

一. Realm是一个更好的手机平台上的数据库, 它是一个易用、更快、非常先进文件数据库,底层使用JNI实现. 支持多种编程环境, 如: Java、Object-C、React Native、Swift、Xamarin。
Realm的官网: https://realm.io
github地址: https://github.com/realm
realm-java库的文档: https://realm.io/docs/java/latest/
下面是其官网的截图 (官网做的非常简洁漂亮,富有设计感. 说实话, 我就是被这个漂亮的网页吸引了, 才使用Realm的):

introduce

Realm的特性:


features

二. 使用
虽说Realm看起来如此美好, 但第一次使用Realm的过程那是相等痛苦.
下面说说Realm的简单用法:

  • 在module的build.gradle文件中添加如下配置 (与realm无关的配置省略)
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        //1. 添加realm插件
        classpath "io.realm:realm-gradle-plugin:1.2.0"
    }
}

//2. 应用realm插件
apply plugin: 'realm-android'

dependencies {
    //3. 添加realm库
    compile 'io.realm:realm-android-library:1.2.0'
}
  • 初始化Realm

public void init(Context appContext, long dbVersion) {
mConfig = new RealmConfiguration.Builder(appContext)
.name("app.realm") //指定realm的文件名称, 会在/data/data/package-name/files/目录下面生成app.realm文件
.encryptionKey(new byte[64]) //base64加密key
.schemaVersion(dbVersion) //realm版本
.build();
mRealm = Realm.getInstance(mConfig);
}
```

  • CURD操作
    Realm规定所有改动操作必须在事务中进行, 即改动操作必须在Realm的beginTransaction()commitTransaction()方法之间进行 或者在executeTransaction方法的参数的回调中执行. 改动操作有: createObject/copyXxx/insert/deleteXxx 等

    **添加操作: **

public Movie add(Movie movie) {
    //如果创建一个新对象, PrimaryKey的值为默认值(整型0), 那么第二次添加数据时, 使用
    //Realm.createObject()/Realm.copyToRealm()/Realm.insert()都会抛出下面的异常,
    //因为第一次插入的数据的PrimaryKey就是0, 而PrimaryKey是不能重复的
    /*
    io.realm.exceptions.RealmPrimaryKeyConstraintException: Value already exists: 0
        at io.realm.internal.Table.throwDuplicatePrimaryKeyException(Table.java:727)
        at io.realm.internal.Table.addEmptyRow(Table.java:414)
        at io.realm.Realm.createObject(Realm.java:681)
     */

    //方式一
    mRealm.beginTransaction();
    //必须设置新的PrimaryKey
    movie.setId(generateNewPrimaryKey()); // TODO: 16/9/2 为了获取新的PrimaryKey进行了一次查询, 有待优化
    mRealm.insert(movie);
    mRealm.commitTransaction();

    //方式二
//    mRealm.executeTransaction(realm -> {
//        //必须设置新的PrimaryKey
//        movie.setId(generateNewPrimaryKey()); // TODO: 16/9/2 为了获取新的PrimaryKey进行了一次查询, 有待优化
//        realm.insert(movie);
//    });

    return movie;
}

//获取最大的PrimaryKey并加一
 private long generateNewPrimaryKey() {
     long primaryKey = 0;
     RealmResults<Movie> results = mRealm.where(Movie.class).findAll();
     if(results != null && results.size() > 0) {
         Movie last = results.last();
         primaryKey = last.getId() + 1;
     }
     return primaryKey;
 }

更新操作

public Movie update(Movie movie) {
    mRealm.beginTransaction();
    //如果操作的对象没有PrimaryKey, 会报错: java.lang.IllegalArgumentException: A RealmObject with no @PrimaryKey cannot be updated: class com.stone.hostproject.db.model.Movie
    Movie dbMovie = mRealm.copyToRealmOrUpdate(movie);
    mRealm.commitTransaction();

    return dbMovie;
}

public Movie updateById(long id, Movie newMovie) {
    //查询
    Movie dbMovie = mRealm.where(Movie.class)
            .equalTo("id", id)
            .findFirst();

    //更新字段
    dbMovie.setName(newMovie.getName());
    dbMovie.setDirectors(newMovie.getDirectors());
    dbMovie.setCasts(newMovie.getCasts());

    //更新到realm中
    mRealm.beginTransaction();
    mRealm.copyToRealmOrUpdate(dbMovie);
    mRealm.commitTransaction();

    return dbMovie;
}

查询操作

 public List<Movie> load() {
      //异步查询
//      mRealm.where(Movie.class).
//              findAllAsync()
//              .asObservable()
//              .observeOn(AndroidSchedulers.mainThread())
//              .subscribe(results -> {
//              });

      //条件查询
//      RealmResults<Movie> results1 = mRealm.where(Movie.class)
//              .greaterThan("year", 2000)
//              .findAllSorted("year", Sort.DESCENDING); //Sort by year, in descending order

      //同步查询所有数据
      return mRealm.where(Movie.class).findAll();
}

删除操作

public void delete(Movie movie) {
    if(movie.getId() < 0) {
        throw new IllegalArgumentException("非法参数: Movie的id不正确");
    }

    //managed, 直接删除
    if(movie.isValid()) {
        mRealm.beginTransaction();
        movie.deleteFromRealm();
        mRealm.commitTransaction();
        return;
    }

    //unmanaged: 先查询, 再删除
    deleteById(movie.getId());
}

public void deleteById(long id) {
    //查询
    Movie dbMovie = mRealm.where(Movie.class)
            .equalTo("id", id)
            .findFirst();

    //删除
    mRealm.beginTransaction();
    dbMovie.deleteFromRealm();
    mRealm.commitTransaction();
}

==========================================
Movie.java文件如下

import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;

public class Movie extends RealmObject  {
    
    //id字段作为主键 (int/long类型的默认值为0, 如果realm已经存在了一个id为0的数据, 那么调用
    //Realm.createObject()/Realm.copyToRealm()/Realm.insert()的时候会冲突, 因为PrimaryKey是惟一的, 不允许重复
    @PrimaryKey
    private long id; //由于上述原因, id必须手动设置, 且不能与realm中已存在的PrimaryKey相同

    private String image;

    private String name;

    private String directors;

    private String casts;

    //如果有带参数的构造方法, 那么无参构造方法必须显式提供
    public Movie() {
    }

    public Movie(String image, String name, String directors, String casts) {
        this.image = image;
        this.name = name;
        this.directors = directors;
        this.casts = casts;
    }

    public Movie(long id, String image, String name, String directors, String casts) {
        this.id = id;
        this.image = image;
        this.name = name;
        this.directors = directors;
        this.casts = casts;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDirectors() {
        return directors;
    }

    public void setDirectors(String directors) {
        this.directors = directors;
    }

    public String getCasts() {
        return casts;
    }

    public void setCasts(String casts) {
        this.casts = casts;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
}

下面是一个CURD操作的完整类(DbManager.java)

import android.app.Application;
import android.content.Context;

import java.util.List;

import io.realm.Realm;
import io.realm.RealmConfiguration;
import io.realm.RealmResults;

public final class DbManager {
    private RealmConfiguration mConfig;
    private Realm mRealm;

    private DbManager() {}

    private static class InstanceHolder {
        private static final DbManager INSTANCE = new DbManager();
    }

    public static DbManager get() {
        return InstanceHolder.INSTANCE;
    }

    /**
     * 初始化Realm, 建议在{@link Application#onCreate()}方法中调用
     * @param appContext
     * @param dbVersion
     */
    public void init(Context appContext, long dbVersion) {
        mConfig = new RealmConfiguration.Builder(appContext)
                .name("app.realm")
                .encryptionKey(new byte[64])
                .schemaVersion(dbVersion)
                .deleteRealmIfMigrationNeeded()
                .build();
        mRealm = Realm.getInstance(mConfig);
    }

    /**
     * 退出应用的时候调用
     */
    public void destroy() {
        if (mRealm != null) {
            if(!mRealm.isClosed()) {
                mRealm.close();
            }
            mRealm = null;
        }
    }

    /**
     * @param movie 要添加的对象
     * @return 返回realm中的对象
     */
    public Movie add(Movie movie) {
        //如果创建一个新对象, PrimaryKey的值为默认值(整型0), 那么第二次添加数据时, 使用
        //Realm.createObject()/Realm.copyToRealm()/Realm.insert()都会抛出下面的异常,
        //因为第一次插入的数据的PrimaryKey就是0, 而PrimaryKey是不能重复的
        /*
        io.realm.exceptions.RealmPrimaryKeyConstraintException: Value already exists: 0
            at io.realm.internal.Table.throwDuplicatePrimaryKeyException(Table.java:727)
            at io.realm.internal.Table.addEmptyRow(Table.java:414)
            at io.realm.Realm.createObject(Realm.java:681)
         */

        //方式一
//        mRealm.beginTransaction();
//        //必须设置新的PrimaryKey
//        movie.setId(generateNewPrimaryKey()); // TODO: 16/9/2 为了获取新的PrimaryKey进行了一次查询, 有待优化
//        mRealm.insert(movie);
//        mRealm.commitTransaction();


//        //方式二
        mRealm.executeTransaction(realm -> {
            //必须设置新的PrimaryKey
            movie.setId(generateNewPrimaryKey()); // TODO: 16/9/2 为了获取新的PrimaryKey进行了一次查询, 有待优化
            realm.insert(movie);
        });

        return movie;
    }

    //获取最大的PrimaryKey并加一
    private long generateNewPrimaryKey() {
        long primaryKey = 0;
        //必须排序, 否则last可能不是PrimaryKey最大的数据. findAll()查询出来的数据是乱序的
        RealmResults<Movie> results = mRealm.where(Movie.class).findAllSorted("id", Sort.ASCENDING);
        if(results != null && results.size() > 0) {
            Movie last = results.last(); //根据id顺序排序后, last()取得的对象就是PrimaryKey的值最大的数据
            primaryKey = last.getId() + 1;
        }
        return primaryKey;
    }

    /**
     *
     * @param movie movie的id, 必须有realm中的对象的id (@PrimaryKey标志的字段)
     * @return 返回更改后的realm中的对象
     */
    public Movie update(Movie movie) {
        mRealm.beginTransaction();
        //如果RealmObject对象没有primaryKey, 会报错: java.lang.IllegalArgumentException: A RealmObject with no @PrimaryKey cannot be updated: class com.stone.hostproject.db.model.Movie
        Movie dbMovie = mRealm.copyToRealmOrUpdate(movie);
        mRealm.commitTransaction();

        return dbMovie;
    }

    public Movie updateById(long id, Movie newMovie) {
        //查询
        Movie dbMovie = mRealm.where(Movie.class)
                .equalTo("id", id)
                .findFirst();

        //更新字段
        dbMovie.setName(newMovie.getName());
        dbMovie.setDirectors(newMovie.getDirectors());
        dbMovie.setCasts(newMovie.getCasts());

        //复制到realm中
        mRealm.beginTransaction();
        mRealm.copyToRealmOrUpdate(dbMovie);
        mRealm.commitTransaction();

        return dbMovie;
    }

    public void delete(Movie movie) {
        if(movie.getId() < 0) {
            throw new IllegalArgumentException("非法参数: Movie的id不正确");
        }

        //managed, 直接删除
        if(movie.isValid()) {
            mRealm.beginTransaction();
            movie.deleteFromRealm();
            mRealm.commitTransaction();
            return;
        }

        //unmanaged: 先查询, 再删除
        deleteById(movie.getId());
    }

    public void deleteById(long id) {
        //查询
        Movie dbMovie = mRealm.where(Movie.class)
                .equalTo("id", id)
                .findFirst();

        //删除
        mRealm.beginTransaction();
        dbMovie.deleteFromRealm();
        mRealm.commitTransaction();
    }

    public List<Movie> load() {
        //异步查询
//        mRealm.where(Movie.class).
//                findAllAsync()
//                .asObservable()
//                .observeOn(AndroidSchedulers.mainThread())
//                .subscribe(results -> {
//                });

        //条件查询
//        RealmResults<Movie> results1 = mRealm.where(Movie.class)
//                .greaterThan("year", 2000)
//                .findAllSorted("year", Sort.DESCENDING); //Sort by year, in descending order

        //同步查询所有数据(根据id倒序排序, 最后添加的在ListView的顶部)
        return mRealm.where(Movie.class).findAllSorted("id", Sort.DESCENDING);
    }
}

references:
https://realm.io
https://realm.io/docs/java/latest/
https://github.com/realm/realm-java

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容

  • Realm 介绍 什么是ORM?Android原生操作数据库的方式是这样的:首先定义一个类继承SQLiteOpen...
    李晓俊阅读 2,379评论 0 0
  • Realm是一个移动端数据库,用来代替SQLite和ORMs。支持跨平台,本文简单介绍Realm在Xamarin....
    MayueCif阅读 1,264评论 2 1
  • 前言 由于最近项目中在用Realm,所以把自己实践过程中的一些心得总结分享一下。 Realm是由Y Combina...
    一缕殇流化隐半边冰霜阅读 73,099评论 213 517
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,133评论 25 707
  • 有了院子种下树后我增加了一个大大的乐趣,就是周末到我的院子浇水、拔草、打扫院子,更大的乐趣是细细观察小树们一枝嫩芽...
    tyoungyc阅读 196评论 0 0