三分钟带你了解Android轻量数据库,GreenDao!

一.GreenDao介绍

纵观整个android发展史,数据库在其中扮演者一个相当重要的角色。入行到现在,从开始自己构建表,自己封装增、删、改、查到后来引用三方库,其中有多少的血泪史不可表述,哈哈哈,毕竟我是一个懒人,自己封装总是很麻烦。

闲话不多说,接下来,迎来今天的主角,轻量数据库“GreenDao”。

GreenDao是一款开源且面向Android的轻便、快捷的ORM框架,可以轻松将对象映射到SQLite库中。众所周知,Android是以面向对象为基准的,GreenDao就做到这点了,它将关系数据库表中的记录映射为对象,以对象的形式展现给我们,我们可以把对数据库的操作转化为对对象的操作,以此来减少我们对数据库表单的繁琐操作,减少bug率。

来看看官方是如何介绍GreenDao的:(原谅我鸡肋的翻译)

1.最牛逼的性能(他们说可能是Android中最快的ORM);

2.提供强大的API,覆盖交互和接入;

3.一丢丢丢丢丢的内存消耗;

4.库的大小不超过100KB,可以减少构建时间还能避免65535方法限制;

5.支持数据库加密,确保用户数据安全;

6.在github中有超过5000star。

卧槽!!!大眼一看,这也太舒服了吧,不用自己编写SQL和解析查询结果,只需要操作对象就ok,还不占用资源,真香。

wait!

我发现了什么?还对协议缓冲区进行了支持,也就是说,如果通过protobuf与服务器通信,则不需要其他映射。常规实体的所有持久性操作均可用于protobuf对象。全能型选手吗?看到这里,我觉得不用的话,实在对不起作者。来搞一手?

二.GreenDao使用

1.集成

在app下gradle文件dependcies添加依赖

implementation "org.greenrobot:greendao:$greendaoVersion"(greendaoVersion为版本号,建议使用最新)
implementation 'com.github.yuweiguocn:GreenDaoUpgradeHelper:v2.1.0'(这个库为数据库版本控制更新)

在project下gradle文件buildscript中添加插件

classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'

记得在app下gradle使用

apply plugin: 'org.greenrobot.greendao'

在app build.gradle中添加数据库版本号

greendao {
    //app数据库版本
    schemaVersion 1
}

如果app需要混淆的话,记得在混淆文件中加入混淆代码

# greendao混淆配置
-keep class org.greenrobot.greendao.**{*;}
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
    public static java.lang.String TABLENAME;
}
-keep class **$Properties
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
    public static void dropTable(org.greenrobot.greendao.database.Database, boolean);
    public static void createTable(org.greenrobot.greendao.database.Database, boolean);
}

sync now冲啊!!!!

2.使用

首先需要先创建数据库,在创建数据库之前,建议先创建数据库更新的帮助类,该类继承DaoMaster.OpenHelper:

package com.bwx.app.db.helper;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

import com.bwx.app.db.data.AccountDbDataDao;
import com.bwx.app.db.data.AppSettingDbDataDao;
import com.bwx.app.db.data.DaoMaster;
import com.bwx.app.db.data.DownLoadDbDataDao;
import com.bwx.app.db.data.UserDbDataDao;
import com.github.yuweiguocn.library.greendao.MigrationHelper;

import org.greenrobot.greendao.database.Database;

/**
 * 数据库升级帮助类 类名称:MySQLiteUpdateOpenHelper
 *
 * @author elank
 * @time 2020/08/13
 * @version 2.0
 */
public final class SQLiteUpdateOpenHelper extends DaoMaster.OpenHelper {
    private static final String TAG = "MySQLiteUpdateOpenHelper";

    public SQLiteUpdateOpenHelper(Context context, String name) {
        super(context, name);
    }

    public SQLiteUpdateOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
        super(context, name, factory);
    }

    @Override
    public void onUpgrade(Database db, int oldVersion, int newVersion) {
        Log.d(TAG, "onUpgrade------->oldVersion = " + oldVersion + "------>newVersion = " + newVersion);
        MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() {

            @Override
            public void onCreateAllTables(Database db, boolean ifNotExists) {
                DaoMaster.createAllTables(db, ifNotExists);
            }

            @Override
            public void onDropAllTables(Database db, boolean ifExists) {
                DaoMaster.dropAllTables(db, ifExists);
            }
        }, *****.class);
    }
}

在onUpgrade方法中,MigrationHelper.migrate();直接复制就可以,第二个参数,就是你创建的数据库实体类的Dao,后边我会说到,方便大家更好理解。然后在application中,创建数据库:

boolean ENCRYPTED = false;    // 是否需要加密 
SQLiteUpdateOpenHelper helper;
        Database db;
        if (ENCRYPTED) {
            helper = new SQLiteUpdateOpenHelper(this, "数据库name“);
            db = helper.getEncryptedWritableDb("数据库密码");
        } else {
            helper = new SQLiteUpdateOpenHelper(this, "数据库name");
            db = helper.getWritableDb();
        }
        DaoSession daoSession = new DaoMaster(db).newSession();
        UserHelper.getInstance().initUserData(this);

同时在application中提供获取Dao的公共方法:daoSession就是上一段代码中的。

/**
 * @Params dbClass=数据对象class
 */
public AbstractDao getDataBaseDao(Class dbClass) {
        if (daoSession == null) {
            return null;
        }
        return daoSession.getDao(dbClass);
    }

数据库实体类的创建:和普通数据类创建一样,只不过加上几个注解就可以使用啦,下边我会给大家说明注解的意思和截图;

package com.bwx.app.db.data;

import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Index;
import org.greenrobot.greendao.annotation.NotNull;
import org.greenrobot.greendao.annotation.Transient;
import org.greenrobot.greendao.annotation.Unique;
import org.greenrobot.greendao.annotation.Generated;

@Entity
public class PeopleDbData {

    @Id(autoincrement = true)
    @Unique
    private Long id;
    @Index
    private int index;
    @NotNull
    private String name;
    private Integer gender;
    private String profession;

    @Transient
    private String custom;
}

注解:

@Entity   标识实体类,GreenDAO会映射成sqlite的一个表,表名为实体类名的大写形式

@Id 标识主键,该字段的类型为long或Long类型,autoincrement设置是否自动增长

@Property       标识该属性在表中对应的列名称, nameInDb设置名称

@Transient      标识该属性将不会映射到表中,也就是没有这列

@NotNull         设置表中当前列的值不可为空

@Convert         指定自定义类型(@linkPropertyConverter)

@Generated   greenDAO运行所产生的构造函数或者方法,被此标注的代码可以变更或者下次运行时清除

@Index    使用@Index作为一个属性来创建一个索引;定义多列索引(@link Entity#indexes())

@JoinEntity     定义表连接关系

@JoinProperty         定义名称和引用名称属性关系

@Keep     注解的代码段在GreenDao下次运行时保持不变

         1.注解实体类:默认禁止修改此类
          2.注解其他代码段,默认禁止修改注解的代码段

@OrderBy        指定排序

@ToMany         定义与多个实体对象的关系

@ToOne  定义与另一个实体(一个实体对象)的关系

@Unique 向数据库列添加了一个唯一的约束

我个人只使用了一部分,因为只是演示。类名标注@Entity,说明这是一个数据库,@Id,这个是必须要有,类的键,可以设置自增长,值须为Long。

这个时候,类已经有了,那我们怎么去设置值呢?get、set方法?那是必须的,但是为啥我没写呢?嘿嘿,这个时候就展示出GreenDao该有的大库风范了。

Rebuild Project来一波------------->

package com.bwx.app.db.data;

import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Index;
import org.greenrobot.greendao.annotation.NotNull;
import org.greenrobot.greendao.annotation.Transient;
import org.greenrobot.greendao.annotation.Unique;
import org.greenrobot.greendao.annotation.Generated;

@Entity
public class PeopleDbData {

    @Id(autoincrement = true)
    @Unique
    private Long id;
    @Index
    private int index;
    @NotNull
    private String name;
    private Integer gender;
    private String profession;

    @Transient
    private String custom;

    @Generated(hash = 999154350)
    public PeopleDbData(Long id, int index, @NotNull String name, Integer gender,
            String profession) {
        this.id = id;
        this.index = index;
        this.name = name;
        this.gender = gender;
        this.profession = profession;
    }

    @Generated(hash = 1838687762)
    public PeopleDbData() {
    }

    public Long getId() {
        return this.id;
    }

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

    public int getIndex() {
        return this.index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public String getName() {
        return this.name;
    }

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

    public Integer getGender() {
        return this.gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    public String getProfession() {
        return this.profession;
    }

    public void setProfession(String profession) {
        this.profession = profession;
    }
}

惊喜不,完全不用我们自己去写,自动生成。同时,你会发现,多了一个Dao类,如下:

原来连dao都自己生成了,这个时候只需要创建一个helper来完成增、删、改、查。

package com.bwx.app.db.helper;


import android.text.TextUtils;
import android.util.Log;

import com.bwx.app.base.application.BwxApplication;
import com.bwx.app.db.data.PeopleDbData;
import com.bwx.app.db.data.PeopleDbDataDao;
import com.bwx.app.utils.ListUtils;

import org.greenrobot.greendao.AbstractDao;

import java.util.List;

public final class PeopleHelper {

    private static final String TAG = "PeopleHelper";
    
    /**
     * 插入数据
     * @param application
     * @param peopleDbData
     */
    public static void insertData(BwxApplication application, PeopleDbData peopleDbData) {
        AbstractDao abstractDao = application.getDataBaseDao(PeopleDbData.class);
        if (abstractDao == null || peopleDbData == null) {
            return;
        }

        try {
            abstractDao.insert(peopleDbData);
        } catch (Throwable t) {
            Log.e(TAG, t.getMessage());
        }
    }

    /**
     * 根据id删除
     * @param application
     * @param id
     */
    public static void deleteFromId(BwxApplication application, Long id) {
        AbstractDao abstractDao = application.getDataBaseDao(PeopleDbData.class);
        if (abstractDao == null || id == null) {
            return;
        }
        abstractDao.deleteByKey(id);
    }

    /**
     * 更新数据
     * @param application
     * @param peopleDbData
     */
    public static void updateData(BwxApplication application, PeopleDbData peopleDbData){
        AbstractDao abstractDao = application.getDataBaseDao(PeopleDbData.class);
        if (abstractDao == null || peopleDbData == null) {
            return;
        }
        
        try {
            abstractDao.update(peopleDbData);
        } catch (Throwable t) {
            Log.e(TAG, t.getMessage());
        }
    }

    /**
     * 根据id查询数据
     * @param application
     * @param id
     * @return
     */
    public static PeopleDbData getDataFromId(BwxApplication application, Long id) {
        AbstractDao abstractDao = application.getDataBaseDao(PeopleDbData.class);
        if (abstractDao == null || id == null) {
            return null;
        }

        PeopleDbData peopleDbData = abstractDao.getSession().queryBuilder(PeopleDbData.class)
                .where(PeopleDbDataDao.Properties.Id.eq(id))
                .build().unique();
        return peopleDbData;
    }

    /**
     * 获取全部数据
     * @param application
     * @return
     */
    public static List<PeopleDbData> getAllData(BwxApplication application) {
        AbstractDao abstractDao = application.getDataBaseDao(PeopleDbData.class);
        if (abstractDao == null) {
            return null;
        }

        List<PeopleDbData> list = abstractDao.getSession().queryBuilder(PeopleDbData.class).build().list();
        return list;
    }
}

这里我只简单写几个最基础的方法,还有更多的方法可以自己去增加,根据自己的业务需要。到这里想必大家都知道该怎么用了,但其中一些类可能还不太明白是干嘛的,例如DaoSession、DAO

greenDAO为我们生成的类中包括DaoMaster,DaoSession和一些实体对应的DAOs,而前两个是greenDAO的机制中核心的接口。

每一个DaoMaster持有一个数据库连接,通过DaoMaster.newSession()方法可以实例化多个Session,这些Session对应同一个数据库连接,但是系统会为每一个Session分配内存,在这片内存中会为实体进行缓存。每一个Session对应一个Identity scope(也就是该库下的一个独立空间),官方文档中提供了一个Hibernate中介绍Session和Identity Scope概念的链接。

从DaoSession中可以获取各实体类的对应DAO,然后就可以进行增删改查的操作了,对于每一个Session中的查询操作都会对查到的实体类做缓存操作,所以对应同一个Session的多次查询操作,如果entity的对象在该Session中有对应缓存则直接使用,而不再从数据库中读取数据并构建新的实体类对象。

首先创建SQLiteUpadteHelper继承DaoMaster.helper,使用该类去创建数据库,具体如何创建我们可以跟着构造看看底层

只需要跟进一层就可以看到,其实OpenHelper继承了DatabaseOpenHelper,重写父类中onCreate方法,在创造这个类的时候传入上下文、数据库名字、是否加密(可选),就会调用到onCreate方法从而去创建db库。

然后通过DaoMaster创建一个DaoSession去关联这个数据库,从而达到该DaoSession去单独管控这一片数据库的空间。

举个简单的例子,假设app是一个公司,DaoMaster就是公司的库存经理,DaoSession就是仓库主管,有多少仓库,就有多少主管;Dao就是主管手下的工人,Entity就是货物,有多少货,就有多少工人。我们所写的helper,就是这个工人为了管理这个货物而做的一个工具。这样来看的话,是不是一下就理解了这些类的分工。

好了,GreenDao的介绍和简单实用我就写到这里,其实还有很多功能由于时间关系,我就不一一写进去了,大家可以自行深入研究,我把api大家留下,感兴趣的猿们自己去看就行了。

GreenDao官网介绍

GreenDao-Api

谢谢大家,您的鼓励是我创作的最大动力!

如有转载,烦请注明出处https://blog.csdn.net/elank0521/article/details/107960705

猜你喜欢

转载自blog.csdn.net/elank0521/article/details/107960705