Realm数据库的使用

写在前面

Realm数据库不同于SQLite,两者可以说是同级的,为什么选择Realm数据库?Android目前流行三方数据库ORM分析及对比。我个人觉得最主要的是两点:1. 访问快,直接操作底层数据;2. 支持跨平台。什么是ORM? object relation model,对象关系映射模型,就是通过使用描述对象和数据库之间映射的元数据,来实现面向对象语言程序中的对象与关系数据库中数据的映射。简单来说,就是一个类对应数据库中的表,一个属性对应数据库中的一列,一个类的对象对应数据库中的一条记录。 参考。基于ORM技术的框架称为ORM框架,它使得使用者更容易理解和操作数据库,但是由于中间需要转换,所以性能上比直接使用SQL语句要慢,另外还需要保存数据对应的类,所以需要更多的内存。

简单使用

RealmGitHube 或者 官网

几个概念

1. 数据模型
  • 一个模型(java中的一个类)表示数据库中的一张表,模型中的字段表示表中的列
  • 模型需要继承RealmObject类
  • 模型实时、自动更新(需要获得当前线程的looper,在主线程中是满足的);操作模型就相当于直接操作数据库中底层数据
2. 事务
  • 所有会使数据发生变化 的操作必须在事务中进行。如:增、删、改
  • 事务分为同步事务和异步事务两种
3. 引用计数
  • Realm实例使用引用计数的方式
  • 生成的Realm实例在使用完后需要手动close。
4. 数据库的迁移

在Realm中如果增加、删除了模型或者模型的字段,需要进行数据库的迁移。这个概念类似于数据库的升级。

添加配置文件

  1. 在project的build.gradle文件中调加依赖
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "io.realm:realm-gradle-plugin:5.12.0"
    }
}
  1. 在app下的build.gradle文件顶部添加对应的插件支持
apply plugin: 'realm-android'

初始化Realm并配置Realm

1. 在application的onCreate()中使用Realm.init()初始化
2. 在application的onCreate()中对Realm进行相关的配置

配置不是必须的,如果不配置,会使用默认配置;但是如果有数据库的迁移,那么是需要配置数据库的。

  1. 使用默认配置

有两种方式可以使用默认配置:

//方式1:
// Get a Realm instance for this thread
Realm realm = Realm.getDefaultInstance();

这样得到的Realm实例使用的就是默认的配置。

//方式二
RealmConfiguration config = new RealmConfiguration.Builder().build();
Realm.setDefaultConfiguration(conf);

默认配置的话,会得到一个名为default.realm数据库,数据库保存地址:data/data/包名/files/default.realm

  1. 自定义配置
// The Realm file will be located in Context.getFilesDir() with name "myrealm.realm"
RealmConfiguration config = new RealmConfiguration.Builder()
  .name("myrealm.realm")
  .encryptionKey(getKey()) //设置密钥
  .schemaVersion(42)  //版本号
  .modules(new MySchemaModule())
  .migration(new MyMigration()) //数据库迁移
  .build();
// Use the config
Realm realm = Realm.getInstance(config);
3. Realm使用完了之后要关闭

一般在activity.onDestroy()中关闭,或者在finally语句块中关闭

try {
        // ... Use the Realm instance ...
    } finally {
        realm.close();
    }

创建模型

一般来说都是写一个类继承RealmObject

public class User extends RealmObject {

    private String          name;
    private int             age;

    @Ignore
    private int             sessionId;

    // Standard getters & setters generated by your IDE…
    public String getName() { return name; }
    public void   setName(String name) { this.name = name; }
    public int    getAge() { return age; }
    public void   setAge(int age) { this.age = age; }
    public int    getSessionId() { return sessionId; }
    public void   setSessionId(int sessionId) { this.sessionId = sessionId; }
}

注意 所有属性修饰符可以为privatepublic, protected ,一般使用private,提供setter/getter方法供外部访问。支持定义普通方法。

字段类型
  • 基本类型:Realm支持 boolean, byte, short, int, long, float, double, String, Date and byte[]的字段类型,其中整形变量byte, short, int, long在Realm会转换为long
  • 继承RealmObject 的类型
  • List只能使用RealmList<? extends RealmObject>
  • 包装类型:Boolean, Byte, Short, Integer, Long, Float and Double
    更详细的字段描述可参考官网
修饰符
  • @primarykey:主键,一个模型中只能由一个主键

  • @Required:表示该字段非空

  • @Ignore:表示忽略该字段,添加 @Ignore 标签后,存储数据时会忽略该字段

  • @Index:添加搜索索引,为字段添加 @Index 标签,插入速度变慢,查询速度变快,支持索引 String、byte、short、int、long、boolean 和 Date字段

事务

在Realm中事务有两种,同步和异步事务,共有三种开启方式

1. 手动开启事务
Realm realm = Reaml.getDefaultInstance();
//开启事务
realm.beginTransaction();
//创建被Realm管理的实例对象,该对象的所有变更都会被直接应用到Realm数据源中
User user = reaml.createObject(User.calss);
//更改数据
user.setUserName("tudou");
//提交事务:所有的修改数据相关的操作只有在执行事务提交之后,才会被写入到数据库
realm.commitTransaction();
//取消事务:取消事务后,所有对数据 的修改都会被取消
realm.cancelTransaction();
2. 同步事务执行块
//这种方式会自动开启事务,提交事务;并在发生错误时取消事务
realm.executeTransaction(new Realm.Transaction(){
   @Override
    public void execute(Realm realm){
        User user = reaml.createObject(User.calss);
        user.setUserName("tudou");
    }
});
3. 异步事务执行块
//使用异步事务,Realm会在后台线程中进行写入操作,并在事务完成时将结构返回调用线程;
//OnSuccess和OnError不是必须的,重载函数的会在事务成功或者失败时在调用线程执行。
RealmAsyncTask asyncTask = realm.executeTransactionAsync(new Realm.Transaction(){
    @Override
    public void execute(Realm realm){
        User user = reaml.createObject(User.calss);
        user.setUserName("tudou");
    }
}, new Realm.Transaction.OnSuccess(){
    @Override
    public void onSuccess(Realm realm){
        //事务执行成功时回调
    }
},new Realm.Transaction.OnError(){
    @Override
    public void onError(Realm realm){
        //事务执行失败时回调
    }
});
//当你退出Activity或者Fragment时,要记得使用RealmAsyncTask取消异步事务;
//如果你在回调函数中更新 UI,那么忘记取消异步事务可能会造成你的应用崩溃
if(asyncTask != null && !asyncTask.isCancelled()){
    asyncTask.cancel();
}

注意

在UI和后台线程同时开启创建write的事务,可能会导致ANR错误。为了避免该问题,可以使用executeTransactionAsync来实现。

数据库操作-增

1. copyToRealm()/createObject()获取自动更新的Realm模型

复制对象到Realm

User user = new User("John");  
user.setEmail("tudou@gmail.com");  
// Copy the object to Realm. Any further changes must happen on realmUser  
mRealm.beginTransaction();  
mRealm.copyToRealm(user);  
mRealm.commitTransaction(); 

注意: copyToRealm()copyToRealmOrUpdate的区别:当Model中存在主键的时候,推荐使用copyToRealmOrUpdate方法插入数据。如果对象存在,就更新该对象;反之,它会创建一个新的对象。若该Model没有主键,使用copyToRealm方法,否则将抛出异常。

获取自动更新的模型

realm.beginTransaction();
User user = realm.createObject(User.class); // Create a new object
user.setName("John");
user.setEmail("john@corporation.com");
realm.commitTransaction();
2. inset() 或者 inserOrUpdate()

如果要插入的是多个数据,比如List,则使用insert()

List<User> users = Arrays.asList(new User("John"), new User("Jane"));

realm.beginTransaction();
realm.insert(users);
realm.commitTransaction();
3. createObjectFromJson()

Realm支持从Json文件中创建模型;需要两者对应

//假如Json文件格式如下:
{
    "musicId": "7",
    "name": "Nostalgic Piano",
}
//则可以创建一个模型类
public class MusicModel extends RealmObject{
    private String musicId;
    private String name;
    //省略了setter/getter方法
}
realm.beginTransaction();
realm.createObjectFromJson(MusicModel.class, musicSourceJson);//musicSourceJson为json文件的字符串。如果json文件中有几层,直接使用最外层即可。
realm.commitTransaction();

数据库操作-查

1. realm.where(User.class)

该方法返回一个RealmQuery<User>对象,大致意思就是得到一张表,然后在表中查询

2. 条件过滤
//所有类型的字段共有的方法
equalTo("name", "John");//第一个参数为字段名,肯定为String,第二个参数为字段的值
notEqualTo();
in(); // 比如:想找名字是否在集合中in("name", new String[]{"Jill", "William", "Trillian"})

//整形字段
between (includes both end points, i.e., it is a bounded interval);
greaterThan();
lessThan();
greaterThanOrEqualTo();
lessThanOrEqualTo();

//String字段
contains();
beginsWith();
endsWith();
like();

//RealmList,String等
isEmpty();
isNotEmpty();
//如果一个字段没有使用 @required 修饰,那么它的值可以为null;可以检查他的值是否为null
isNull();
isNotNull()
3. 逻辑判断
or();//使用or()的使用要配合beginGroup()--->endGroup()使用
and();//默认支持的
not();
RealmResults<User> r = realm.where(User.class)
                            .greaterThan("age", 10)  // implicit AND
                            .beginGroup()
                                .equalTo("name", "Peter")
                                .or()
                                .contains("name", "Jo")
                            .endGroup()
                            .findAll();
4. findXxxx()

上几步操作返回的是RealmQuery<User>对象,调用该对象的findXxx()返回查询的结果,一个RealmResults<User>对象:

findAll();//查找出所有满足条件的记录,返回一个RealmResults<> set
findFirst();//查找出满足条件的第一个结果,RealmQuery<User>对象
findAllAsync();//异步查找结果
5. 其他用法

还可以支持对查询结果进行sort()等多种操作,设置监听等,更多请参考官网。

数据库操作-删

删除操作也是需要在事务中进行的。

1. 使用deleteFromRealm()
//先查找到数据,然后再删除
final RealmResults<User> userList = mRealm.where(User.class).findAll();  
mRealm.executeTransaction(new Realm.Transaction() {  
  @Override  
  public void execute(Realm realm) {  
      userList.get(0).deleteFromRealm();  
  }  
}); 
2. 使用 deleteFromRealm(int index)
mRealm.executeTransaction(new Realm.Transaction() {  
  @Override  
  public void execute(Realm realm) {  
      userList.deleteFromRealm(0);  
  }  
});
3. 其他方法
userList.deleteFirstFromRealm(); //删除user表的第一条数据  
userList.deleteLastFromRealm();//删除user表的最后一条数据  
results.deleteAllFromRealm();//删除user表的全部数据
mRealm.delete(MusicModel.class); //直接删除一张表

数据库操作-改

修改操作也是需要在事务中进行的。先查找到数据,然后由于模型是可以自动更新的,直接调用setter方法就可以更改数据了。

mRealm.executeTransaction(new Realm.Transaction() {  
    @Override  
    public void execute(Realm realm) {  
        //先查找后得到User对象  
        User user = mRealm.where(User.class).findFirst();  
        user.setAge(26);  
    }  
}); 

数据库的迁移

当数据库新增了模型或者模型中的字段新增、删除时要进行数据库的迁移。一般情况下,是在刚启动APP的时候,磁盘中已经存在一个Realm数据库了,这个时候就需要进行数据库的迁移。所以数据库的迁移动作一般在application中的onCreate()有两个步骤:

1. 写一个类继承RealmMigration,重写migrate()

migrate()完成数据库的迁移定义

public class MyMigration implements RealmMigration {
  @Override
  public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {

     // DynamicRealm exposes an editable schema
     RealmSchema schema = realm.getSchema();

     // Migrate to version 1: Add a new class.
     // Example:
     // public Person extends RealmObject {
     //     private String name;
     //     private int age;
     //     // getters and setters left out for brevity
     // }
     if (oldVersion == 0) {
        schema.create("Person")
            .addField("name", String.class)
            .addField("age", int.class);
        oldVersion++;
     }

     // Migrate to version 2: Add a primary key + object references
     // Example:
     // public Person extends RealmObject {
     //     private String name;
     //     @PrimaryKey
     //     private int age;
     //     private Dog favoriteDog;
     //     private RealmList<Dog> dogs;
     //     // getters and setters left out for brevity
     // }
     if (oldVersion == 1) {
        schema.get("Person")
            .addField("id", long.class, FieldAttribute.PRIMARY_KEY)
            .addRealmObjectField("favoriteDog", schema.get("Dog"))
            .addRealmListField("dogs", schema.get("Dog"));
        oldVersion++;
     }
  }
}
2. 设置配置信息,并让Realm执行数据迁移动作
RealmConfiguration config = new RealmConfiguration.Builder()
    .schemaVersion(2) // Must be bumped when the schema changes
    .migration(new MyMigration()) // Migration to run instead of throwing an exception
    .build();

//       为Realm设置最新的配置
Realm.setDefaultConfiguration(conf);
//    告诉Realm数据需要迁移了
        try {
            Realm.migrateRealm(conf);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

总结:

使用Realm数据库的步骤:1,2,3,4,5。

  1. 在项目中配置
  2. 初始化Realm并配置Realm、获取Realm的实例。
  3. 对数据库进行增、删、改、查等操作。
  4. 如果磁盘中已经有数据库了,在初始化后需要对数据库进行迁移
  5. 在不使用时,需要关闭数据库连接。
  6. 一般可以写一个帮助类来辅助完成数据库的相关操作。

参考

Realm for Android 使用入门
【Android】Realm详解

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页