美文网首页数据处理安全
Realm使用入门 (一)

Realm使用入门 (一)

作者: 元亨利贞o | 来源:发表于2016-09-03 01:13 被阅读6642次

一. 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

相关文章

网友评论

    本文标题:Realm使用入门 (一)

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