GreenDao概述
如果Android项目中要使用GreenDAO框架,需要先创建一个Java项目用于生成实体类和DAO类,然后在Android项目中使用这些类,在此过程中分别需要对Android项目添加GreenDAO的核心包依赖和对Java项目添加generator包依赖,所以解析GreenDAO的源码需要解析两部分,而这里只解析GreenDAO核心包在Android项目中的工作原理,generator包中的原理很简单,总的来说有四个作用:就是用于生成实体类、DAO类、建立多表之间的关联以及配置实体类的接口和序列化功能
在Android项目中用到的最核心的四个类就是:DaoMaster、DaoSession、实体类、实体Dao类。
这四个核心类的功能体系如下图所示:
DaoMaster
GreenDao框架管理类,该类对数据库相关管理操作进行封装
我们知道在使用GreenDAO时候,我们的入口点就是通过DaoMaster的静态内部类DevOpenHelper来创建一个DevOpenHelper对象
而DevOpenHelper对象又是什么呢?我们都知道在使用SQLite的时候,我们必须通过继承SQLiteOpenHelper类并且实现它内部的一些方法来创建数据库,而这里仅仅通过DevOpenHelper类就成功创建了一个文件名为”students-db”的数据表,那么内部又是怎么实现的呢?我们可以看看DaoMaster类的源码:
从DaoMaster中我们可以发现,DaoMaster除了具有创建表和删除表的两个功能外,还有两个内部类,分别为OpenHelper和DevOpenHelper,OpenHelper继承于SQLiteOpenHelper用于创建所有的数据库表;DevOpenHelper继承于OpenHelper用于数据库升级,而重写的onCreate()
方法中调用了createAllTables(db,false);
方法来创建数据表,而createAllTables()
方法中是通过调用StudentDao静态方法来创建表的StudentDao.createTable(db, ifNotExists);
我们点进这个方法中去看个究竟
发现它内部就是通过sql语句来创建表的,只不过GreenDAO帮我们封装好了,而且你会发现删除表其实也一样:
好了,现在我们知道了通过DevOpenHelper是怎么创建表的,而细心的同学会发现在DevOpenHelper类中实现了onUpgrade()
方法,就是更新数据库的方法,它在更新数据表的时候会把以前的数据表删除后再重新创建,所以这个你必须注意,当我们在利用GreenDAO更新数据表的时候,如果你想以前表中的数据保存下来的话,我们必须自己封装一个方法。
接下来就是newSession()
方法了,这个当然就是得到DaoSession实例了,关于DaoSession实例,GreenDAO官方建议不要重新创建新的实例,保持一个单例的引用即可。好了,DaoMaster源码看完了,接下来就是看它的父类AbstractDaoMaster
的源码了,它的源码如下:
看这个类的代码,其中最让我们受关注的无非就是这一行了
这里定义了一个Map集合,Key是继承自AbstractDao类的字节码对象,Value则为DaoConfig对象。每个AbstractDao对应着一个DaoConfig,然后保存在Map< Class<? extends AbstractDao<?, ?>>, DaoConfig> daoConfigMap中,DaoConfig这个类的作用,一是通过反射的方式获取到AbstractDao对应的表名、表中所有字段(主键、非主键greendao中用Property对象来保存一个字段的信息)等相关信息,然后利用这些信息创建了辅助类TableStatements的一个实例,TableStatements这个类的作用是创建操作table的SQL语句;二是获取该表对应的缓存处理实例。
而往这个Map集合中put数据是通过这个方法registerDaoClass()
:
所以Map的功能现在很清楚了,就是为每一个EntityDao字节码对象建立与之对应的db数据库的映射关系,从而管理所有的EntityDao类。而这个方法在哪里调用了呢?我们回到DaoMaster的源码中,发现在DaoMaster类的构造方法中调用了,并且传入了Student.class
,所以我们在创建DaoMaster对象的时候也同时为EntityDao类和相应的数据库db建立好了关联。
DaoSession
从上面可知DaoSession对象是通过master.newSession();
创建的。DaoSession对象是连接GreenDao框架到SQLite数据库的纽带,通过该对象我们可以得到一个与数据库某个表相关的操作对象xxxDao。我们看看DaoSession源码,发现它也有一个抽象的父类AbstractDaoSession,我们来看看DaoSession的源码:
就那么几行,其中最主要的一个方法就是通过getStudentDao()
来得到StudentDao实例,而创建一个StudentDao对象正是在DaoSession的构造方法中,其中有这么一行:
这个正是从在DaoMaster创建的Map集合中取出key
为StudentDao.class
的DaoConfig对象,刚刚就说了Map集合中保寸了StudentDao类对应的数据库db的关系映射,而这个DaoConfig对象正是管理了对应的db对象。然后把这个DaoConfig传给StudentDao(studentDaoConfig, this)
,所以这就说明了我们使用StudentDao对象来进行数据库上的CRUD操作而对应的数据库也会变化的原因,这个过程实际上就是在间接操作数据库。
好了,接下来就是看看它的父类了:
这个类比较长,所以我删除了几个方法,这不影响理解的
可以看到它的父类中,大部分方法都是进行CRUD操作的,而事实上我们在进行CRUD操作都是通过StudentDao对象来进行的,实际上这两种做法没有区别,因为它内部本身就是通过dao对象来进行CRUD操作的,大家看看这些方法的返回值就知道了。
到此,我们只看到了DaoSession源码表面上的功能,这些功能就是它管理了指定模式下所有可用的DAO对象,并且提供了getter方法供我们得到这些DAO对象,它还提供了一些CRUD方法。实际上DaoSession和StudentDao在调用CRUD的方法进行CRUD操作时,其中的查询操作就是最特别的,为什么呢?原因是GreenDao在查询这块加了缓存,有趣吧,GreenDao在查询时使用了弱引用WeakReference
,假如第一次查询时候我查询了小明这个Student的数据,那么它将把小明加入一个SparseArray<WeakReference<Q>>
的集合中,下次如果再次查询小明这个学生的时候,将立即会返回这个引用从而不必再查询数据库(前提是GC还没回收这些引用)。
这个缓存的代码是在AbstractQueryData
类中,如下:
Entity(实体类)
对于实体类,这没什么可讲的,就是一个Bean,一个实体类对应一张表,实体类里面有对应各个字段的getter和setter方法
EntityDao(实体Dao类)
由生成器生成的数据库操作类,它继承于AbstractDao,封装了所有对数据库表进行增删改成的方法。可以这么说,我们之所以使用GreenDao管理本地数据库无需与SQL语句打交道,就是因为GreenDao框架在这一层已经对大部分数据库操作SQL语句进行了封装。
同样,它也有一个抽象的父类AbstractDao,我们先看看StudentDao类的源码:
其中bindValues()
这个方法就是绑定实体的属性名和表中的字段名的,还有比较重要的就是这个静态内部类Properties,该类中分别对每一个实体类的属性都创建了一个Property对象,而我们可以根据Property来得到这个属性对应表中的列名、是否为主键等值,其中还包括了一些方法,比如判断表中某个字段的值是否和value相等:eq(Object value);
Property源码如下:
而AbstractDao源码中主要是一些CRUD方法和其它的一些方法,源码太长了,避免影响篇幅,我删了一部分:
好了,核心类已经介绍完了
缓存操作
上面在讲到DaoConfig类的作用的时候,有说到它有获取该表对应的缓存处理实例的作用,那么,它是如何缓存的过程,在DaoSession的构造方法中就有为每个Dao初始化缓存的操作了:
下面来看看DaoConfig类关于缓存的一些代码:
可见它是由IdentityScope接口来实现的,它有两个实现类:IdentityScopeLong类和IdentityScopeObject类,下面看看IdentityScopeObject类:
在执行插入操作时,会进行缓存,我们从AbstractDao类中代码可知:
给操作的bean更新字段_id的值:
缓存操作:IdentityScope键值对,key为表中主键,value为bean
可能会问,identityScope从哪来的,下面看:
当query操作时:
总结
我们来看看使用GreenDAO的基本步骤:
GreenDao的逻辑:
- 实例化一个SQLiteOpenHelper对象,以便建立与指定数据库(如”testDb”)之间的连接;
- 调用SQLiteOpenHelper的getWritableDatabase()方法以读写方式打开所连接的数据库;
- 通过获得的数据库对象SQLiteDatabase来创建GreenDao框架管理者DaoMaster对象;
- 调用DaoMaster的newSession()方法实例化一个数据库会话对象DaoSession;
- 通过DaoSession对象获得最终能够操作数据库表的xxxxDao对象”
GreenDao优势
模板代码生成
GreenDao官方为什么说自己的数据库框架运行快呢,首先,第一点这个框架不像其他框架通过运行期反射创建ORM映射,而是通过freemarker模板方式在编译期之前帮你生成可用的和数据库生成有关的表帮助对象,所以说这第一点就比其他数据库框架的速度快。
模板就是把共性(固定不变的)的东西提取出来反复使用,节约时间 提高开发效率。现在主流的模板技术包括:FreeMarker和Velocity,模板技术推崇一种模式:输出=模板+数据。
FreeMarker最开始被MVC Web框架用来生成HTML页面,但它的用途不仅限于HTML或者Web领域,比如本文所要介绍的生成JavaBean源代码。
与其他框架的比较
ormlite
基于注解和反射的的方式,导致ormlite性能有着一定的损失(注解其实也是利用了反射的原理)
优点:
文档较全面,社区活跃,有好的维护,使用简单,易上手。
缺点:
基于反射,效率较低
GreenDao
优点:
效率很高,插入和更新的速度是ormlite的2倍,加载实体的速度是ormlite的4.5倍。
文件较小(<100K),占用更少的内存 ,但是需要create Dao,
操作实体灵活:支持get,update,delete等操作
缺点:
学习成本较高。其中使用了一个java工程根据一些属性和规则去generate一些基础代码,类似于javaBean但会有一些规则,另外还有QueryBuilder、Dao等API,所以首先要明白整个过程,才能方便使用。没有ORMLite那样封装的完整,不过greenDao的官网上也提到了这一点,正是基于generator而不是反射,才使得其效率高的多。
参考博文链接:
http://blog.csdn.net/u010687392/article/details/48465315
http://blog.csdn.net/andrexpert/article/details/53539417
http://www.jianshu.com/p/09ad8040c996
http://blog.csdn.net/xushuaic/article/details/24434881