Android数据缓存框架 - 切换为GreenDao数据库

136 阅读3分钟

本文正在参加「技术专题19期 漫谈数据库技术」活动

数据库技术博大精深,是当今互联网的基础。前有DB2,后有MySQL、Oracle,然后数据库ORM框架也应运而生。没错,我们这一期讲一讲数据库的ORM技术。

什么是ORM?ORM,全称为Object-Relational Mapping(对象关系映射),由于数据库操作使用到SQL,而SQL是给运维用的,我们程序直接拼接SQL则异常繁琐。所以,就有人提出,这部分繁琐的事情能不能交给框架来做?答案是肯定的。

要理解ORM,首先要掌握Java中比较重要的一个概念,泛型。没有它,就没法很好的开发通用型软件架构。泛型,本质上还是对事物进行了抽象。比如我们现在没法实现的伟大事业,我们可以先想想,它大概是怎样的?比如改造火星。有句话叫做,想象力比知识更重要,这就是抽象的魅力所在。

ORM框架,一定是万能的。给我Book的对象我就能存Book,给我Note的对象我就能存Note。即我使用程序员容易理解的对象模型,来直接操作数据库,那么DAO,数据访问对象,就是桥梁。它是直接跟数据库和SQL打交道的,我们在上层定义一个抽象层来连接真实业务。

在Android端,就有这么一个很好的ORM框架,来帮助我们将数据存储到数据库,它就是GreenDao。我们来看看怎么使用吧!

项目依赖GreenDao的插件

在项目根目录的build.gradle依赖插件

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

并在app模块的build.gradle使用它

apply plugin: 'org.greenrobot.greendao'
android {
    // 定义APT生成代码的位置和包名
    greendao {
        schemaVersion 1 daoPackage 'com.xx.greendao'
        targetGenDir 'src/main/java'
    }
}

app模块依赖GreenDao的包

dependencies {
    implementation 'org.greenrobot:greendao:3.2.2' 
    implementation 'org.greenrobot:greendao-generator:3.2.2'
}

定义实体类

@Entity 
public class Note {
    @Id(autoincrement = true) private long id;
    private String text;
    private String comment;
    private Date date;
}

在Application中初始化数据库

DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "note", null); 
SQLiteDatabase db = helper.getWritableDatabase();
DaoMaster master = new DaoMaster(db);
DaoSession daoSession = master.newSession();
NoteDao noteDao = daoSession.getNoteDao();

通过DaoSession拿到操作具体某张表的DAO。

打住,不好意思,搞错了。我们今天不完全是讲解怎么用GreenDao数据库的,这样使用的文章很多。 增删改查都是通过调用dao的方法就可以了。言归正题,我们自定义的数据缓存框架怎么切换到GreenDao进行缓存?

定义GreenDaoDatabaseCacheRepository

package dora.cache.repository

import android.content.Context
import dora.cache.holder.*
import me.itangqi.greendao.DaoSession

abstract class GreenDaoDatabaseCacheRepository<T>(context: Context)
    : BaseDatabaseCacheRepository<T>(context) {

    override fun createCacheHolder(clazz: Class<T>): CacheHolder<T> {
        return GreenDaoCacheHolder<T>(getDaoSession(), clazz)
    }

    override fun createListCacheHolder(clazz: Class<T>): CacheHolder<MutableList<T>> {
        return GreenDaoListCacheHolder<T>(getDaoSession(), clazz)
    }

    abstract fun getDaoSession() : DaoSession
}

定义两个CacheHolder

package dora.cache.holder

import de.greenrobot.dao.AbstractDao
import dora.db.OrmLog
import dora.db.builder.Condition
import me.itangqi.greendao.DaoSession

class GreenDaoCacheHolder<T>(var session: DaoSession, var clazz: Class<T>) : CacheHolder<T> {

    private lateinit var dao: AbstractDao<T, Long>

    override fun init() {
        dao = session.getDao(clazz) as AbstractDao<T, Long>
    }

    override fun queryCache(condition: Condition): T? {
        return session.callInTx {
            dao.queryRaw(condition.selection, *condition.selectionArgs)[0]
        }
    }

    override fun removeOldCache(condition: Condition) {
        try {
            dao.deleteInTx(queryCache(condition))
            OrmLog.d("removeOldCache:true")
        } catch (e: Exception) {
            OrmLog.d("removeOldCache:false")
        }
    }

    override fun addNewCache(model: T) {
        try {
            dao.insertInTx(model)
            OrmLog.d("addNewCache:true")
        } catch (e: Exception) {
            OrmLog.d("addNewCache:false")
        }
    }

    override fun queryCacheSize(condition: Condition): Long {
        return session.callInTx {
            dao.count()
        }
    }
}
package dora.cache.holder

import de.greenrobot.dao.AbstractDao
import dora.db.OrmLog
import dora.db.builder.Condition
import me.itangqi.greendao.DaoSession

class GreenDaoListCacheHolder<T>(var session: DaoSession, var clazz: Class<T>) : ListCacheHolder<T>() {

    private lateinit var dao: AbstractDao<T, Long>

    override fun init() {
        dao = session.getDao(clazz) as AbstractDao<T, Long>
    }

    override fun queryCache(condition: Condition): MutableList<T>? {
        return session.callInTx {
            dao.queryRaw(condition.selection, *condition.selectionArgs)
        }
    }

    override fun removeOldCache(condition: Condition) {
        try {
            dao.deleteInTx(queryCache(condition))
            OrmLog.d("removeOldCache:true")
        } catch (e: Exception) {
            OrmLog.d("removeOldCache:false")
        }
    }

    override fun addNewCache(models: MutableList<T>) {
        try {
            dao.insertInTx(models)
            OrmLog.d("addNewCache:true")
        } catch (e: Exception) {
            OrmLog.d("addNewCache:false")
        }
    }

    override fun queryCacheSize(condition: Condition): Long {
        return session.callInTx {
            dao.count()
        }
    }
}

以上一个是非list模式的,一个是list模式的。切换数据库ORM框架主要就是去重写这两个CacheHolder,用该数据库dao的方法来实现我们的CacheHolder接口。BaseDatabaseCacheRepository更详细的使用,也看我的另两篇文章【Android数据缓存框架 - 切换为Room数据库】juejin.cn/post/715883… 和 【Android数据缓存框架 - 内置ORM功能】juejin.cn/post/713976…