greenDAO的使用总结

1、简述

greendao 查询并更新单个数据 greendao数据库位置_SQL

图片来自greenDAO官网

greenDAO是由greenRobot(大名鼎鼎的EventBus也是出自他们家)出品的一个ORM(对象关系映射)的SQlite数据库操作框架。其利于注解和JavaBean,可以直接生成一个类相对应的数据表。并可以自动生成对该表操作的对应DAO类。除此之外,greenDAO很好的支持了数据库升级,以及sqlcipher数据库加密。通过greenDAO,我们可以更方便的操作数据库。

本文以greenDAO3.0.1为例,介绍一下greenDAO的使用。

2、在项目中集成greenDAO

(1)首先在整个项目的gradle中添加如下代码:

buildscript {
    repositories {
        jcenter()
        mavenCentral() // add repository
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.1'
        classpath 'org.greenrobot:greendao-gradle-plugin:3.0.0'// add plugin
    }
}

(2)在app的Gradle中添加:

apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin

greendao {
    //greenDAO操作的数据库版本号,用于升级数据库用
    schemaVersion 1
    //自己指定,自动生成的DAO类所存储的文件夹名称
    daoPackage 'com.xxx.xxx.greendaodemo.greendao'
    targetGenDir 'src/main/java'
}
dependencies {
    compile 'org.greenrobot:greendao:3.0.1'
    compile 'org.greenrobot:greendao-generator:3.0.0'
    compile 'net.zetetic:android-database-sqlcipher:3.5.2'
}

注意:schemaVersion必须大于等于1。否则报错:

java.lang.IllegalArgumentException: Version must be >= 1, was 0

因为在SQLiteOpenHelper中有如下代码:

public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
        DatabaseErrorHandler errorHandler) {
    if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);

    mContext = context;
    mName = name;
    mFactory = factory;
    mNewVersion = version;
    mErrorHandler = errorHandler;
}

3、注解类

接下来,我们需要创建一个JavaBean类,并使用greenDAO的注解来帮忙生成相应的DAO类。主要其实是介绍greenDAO下几个常用注解的使用。

(1)Entity注解

用于类之上,表示该类会被greenDAO映射为一个表。默认使用的表名即是类名。

例如我们这里有一个People类使用Entity如下:

@Entity
public class People {

    private String name;

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

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

那么我们在程序跑起来后,去查看一下People表。如下:

greendao 查询并更新单个数据 greendao数据库位置_Database_02

当然,你也可以自己指定表名。通过nameInDb字段指定即可,还是之前的People类,我们把表名指定为PeopleTable试一下(注意这里涉及到数据库升级,下一篇会介绍)。如下:

@Entity(nameInDb = "PeopleTable")
public class People {

    private String name;

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

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

再查看下之后生成的表:

greendao 查询并更新单个数据 greendao数据库位置_Database_03

这里我们就可以看到PeopleTable表了。

(2)Id

用Id注解的字段,会作为主键,其自带自增属性。主键类型最好使用Long包装类型,不要使用long数据类型。否则在插入多条数据时可能会引起程序崩溃。

报如下错误:

android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: PeopleTable._id

示例如下:

@Id
private Long autoId;

生成的表中会有如下字段:

greendao 查询并更新单个数据 greendao数据库位置_Database_04

这就是生成的主键字段名。这个字段名是由于其作为主键,GreenDao统一给定的字段名,即_id。

很明显这不是我们想要的字段名,我们希望这里可以与变量名一致,即autoId。那么该如何做呢?看下面一个注解。

(3)Property

其实这里我们还是需要通过nameInDb来重新设置。只是之前的Entity是注解类的。我们这里就需要Property注解来对变量进行注解。

如下:

@Property(nameInDb = "autoId")
@Id
private Long autoId;

我们来看一下效果:

greendao 查询并更新单个数据 greendao数据库位置_数据库_05

(4)Transient

有时候我们的类中可能会有些内容我们不想让他们被加入到表中。比如我在Person类中有两个常量:

public static final String SEX_MAN = "Man";
public static final String SEX_WOMAN = "Woman";

我不做任何处理,直接跑程序。由于greenDAO会自动为类中的字段添加getter和setter方法。于是就出现了如下这种问题情况:

greendao 查询并更新单个数据 greendao数据库位置_数据库_06

报错:

greendao 查询并更新单个数据 greendao数据库位置_数据库_07

你个常量你是不能给他重新赋值的。于是这就需要Transient注解了。添加了该注解就不会生成表中的列,不会将该变量持久化,greenDAO也不会自动为他生成getter和setter方法了。

(5)Unique

使用这个注解可以为相应变量的列添加唯一性约束。比如我们的程序中经常有用户表。而UserId一定是唯一的。我们就可以为UserId添加一下这个注解。

4、操作数据库前要做的事

有了要操作的实体类。接下来我们就希望通过greenDAO把他映射到数据库,进而进行增删改查操作了。但别急,我们先得做一下几个事情。

(1)创建一个数据库的OpenHelper。

示例如下:

DaoMaster.DevOpenHelper mDevOpenHelper = new DaoMaster.DevOpenHelper(
                    mContext,
                    "GreenDaoDb",
                    null
            );

这里主要是通过OpenHelper来指定你要操作哪一个数据库。greenDAO的OpenHelper有2个:DevOpenHelper,OpenHelper。

注意,greenDAO特别对DevOpenHelper做了如下说明:

WARNING:Drops all table on Upgrade!Use only during development.

DevOpenHelper会在升级时删除所有的表,因此建议只在开发时使用它。

这是什么意思呢?我们来看一下OpenHelper和DevOpenHelper的源码就知道了:

/**
     * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} -
     */
    public static abstract class OpenHelper extends DatabaseOpenHelper {
        public OpenHelper(Context context, String name) {
            super(context, name, SCHEMA_VERSION);
        }

        public OpenHelper(Context context, String name, CursorFactory factory) {
            super(context, name, factory, SCHEMA_VERSION);
        }

        @Override
        public void onCreate(Database db) {
            Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION);
            createAllTables(db, false);
        }
    }

    /** WARNING: Drops all table on Upgrade! Use only during development. */
    public static class DevOpenHelper extends OpenHelper {
        public DevOpenHelper(Context context, String name) {
            super(context, name);
        }

        public DevOpenHelper(Context context, String name, CursorFactory factory) {
            super(context, name, factory);
        }

        @Override
        public void onUpgrade(Database db, int oldVersion, int newVersion) {
            dropAllTables(db, true);
            onCreate(db);
        }
    }

可以看到DevOpenHelper实际是继承于OpenHelper的,它覆盖了OpenHelper中的一个方法onUpgrade。使用过原生数据库的朋友们对这个方法应该不陌生。这个方法是在数据库升级时调用。DevOpenHelper在该方法中调用了dropAllTables方法删除了所有的表。之后又通过onCreate方法,onCreate方法中调用createAllTables创建了所有的表。

(2)通过这个OpenHelper获取到一个SQLiteDatabase对象。

示例如下:

SQLiteDatabase db = mOpenHelper.getReadableDatabase();

greenDAO中提供了4种方法来获取SQLiteDatabase对象,分别是getReadableDatabase(获取一个可读数据库);getWriteableDatabase(获取一个可写数据库);getEncryptedReadableDb(获取一个加密可读数据库);getEncryptedWriteableDatabase(获取一个加密可写数据库)。

关于加密这一块,会在本文后面一块中说明。

(3)创建一个DaoMaster对象,并将SQLiteDatabase对象传入。

示例:

DaoMaster daoMaster = new DaoMaster(db);

DaoMaster是greenDAO使用的入口。其代表一个数据库连接,并管理着这个数据库、版本、与该数据库有关的DAO类。


(4)通过DaoMaster对象获取到DaoSession对象。

示例:

DaoSession daoSession = daoMaster.newSession();

DaoSession管理着DAO对象,用于获取DAO对象,进而对数据库中的相应表进行操作。DaoSession可以建立多个,但每个都属于同一个数据库连接。

5、增删改查

上面最后一步,我们获取到了DaoSession对象。我们可以通过DaoSession对象获取DAO类的实体对象了。

DAO类是干嘛的呢?DAO类由greenDAO对于Entity类自动生成,封装了相应的增删改查方法。换句话说,我们就是依赖DAO类对ORM后的数据表进行增删改查的。

对于增删改查操作,我们这里只列举几个常见的api。其余的可以自己去查看greenDAO的api文档来使用,这一块并不难。

(1)增

People people = new People();
Random random = new Random();
people.setName(
       "姓名-"+ random.nextInt(10000)
);
daoSession.getPeopleDao().insert(
       people
);

(2)删

根据主键删除某一个元素:

daoSession.getPeopleDao().deleteByKey(1L);

删除所有元素:


daoSession.getPeopleDao().deleteAll();

(3)改

People people = new People();
Random random = new Random();
people.setName(
       "姓名-"+ random.nextInt(10000)
);
people.setAutoId(1);
daoSession.getPeopleDao().update(people);

(4)查

List<People> peopleList = daoSession
                .getPeopleDao()
                .queryBuilder()
                .orderDesc(PeopleDao.Properties.AutoId)
                .where(PeopleDao.Properties.AutoId.eq(1))
                .build()
                .list();

6、数据库加密

之前我们提到过,方法getEncryptedReadableDb(获取一个加密可读数据库);getEncryptedWriteableDatabase(获取一个加密可写数据库)。这两个方法的不同之处就在于参数中需要多传入一个key,这个key的内容由你自己指定。可以认为是一个加密密码。同样的增删改查都需要依赖于这个加密的Database对象来操作。其内部是基于SQLCipher对数据库进行加密的。

另外注意,要使用这两个方法必须引入加密依赖库:

compile 'net.zetetic:android-database-sqlcipher:3.5.2'

否则会报如下错误:

java.lang.NoClassDefFoundError: org.greenrobot.greendao.database.DatabaseOpenHelper$EncryptedHelper

示例:

public Database getEncryptedWritableDatabase() {
        if (mOpenHelper == null) {
            mOpenHelper = new DaoMaster.DevOpenHelper(
                    mContext,
                    DBController.getDBName(mContext),
                    null
            );
        }
        Database db = mOpenHelper.getEncryptedWritableDb("EncryptedDbKey");
        return db;
    }

如果我们使用了加密数据库插入一个数据,那么就无法预览到成功插入后的数据了,如下:

greendao 查询并更新单个数据 greendao数据库位置_greendao 查询并更新单个数据_08

现在你什么也预览不到了。

篇幅有限,本篇先介绍到这里。