========
greenDAO is a light & fast ORM solution for Android that maps objects to SQLite databases. Being highly optimized for Android, greenDAO offers great performance and consumes minimal memory.
1. 轻量、快速的ORM(Object Relation Mapping对象关系映射)解决方案,将实体对象映射到SQLite数据库中
2. Android开发中数据库操作的最佳方案
3. 提供高性能、消耗低内存
Home page, documentation, and support links: http://greendao-orm.com/
greenDAO has a unique set of features:
greenDAO is available on Maven Central. Please ensure that you are using the latest versions by checking here and here
Gradle dependency for your Android app:
compile 'de.greenrobot:greendao:2.0.0'
Gradle dependency for your Java generator project:
compile 'de.greenrobot:greendao-generator:2.0.0'
(在Android Studio如何引用greendao)
Those features are already here for you to try out. Note: Documentation and test coverage may be lacking, and the API may change in the future.
EventBus is a central publish/subscribe bus for Android with optional delivery threads, priorities, and sticky events. A great tool to decouple components (e.g. Activities, Fragments, logic components) from each other.(greenrobot团队的另一有名开源项目)
greenrobot-common is a set of utility classes and hash functions for Android & Java projects.
Follow us on Google+ to stay up to date.
——————————-华丽的分割线———————————-
For the same given entity, greenDAO inserts and updates entities over 2 times faster, and loads entities 4.5 times faster for loading entities than ORMLite. For typical applications the loading speed is the most important.
(比起ORMLite快,同样的数据,更新是它的两倍,查询是它的4.5倍)
greenDAO 使用「Code generation」的方式
DAO CODE GENERATION PROJECT
这是其核心概念:为了在我们的 Android 工程中使用 greenDAO ,我们需要另建一个纯 Java Project,用于自动生成后继 Android 工程中需要使用到的 Bean、DAO、DaoMaster、DaoSession 等类。
CORE CLASSES & MODELLING ENTITIES
从https://github.com/greenrobot/greenDAO上下载整个完整的项目,然后导入到Android Studio中去,修复参数配置,最终在IDE中完整的项目结构目录如下:
Entity simple = schema.addEntity("SimpleEntity");
simple.addIdProperty();
simple.addBooleanProperty("simpleBoolean");
simple.addByteProperty("simpleByte");
simple.addShortProperty("simpleShort");
simple.addIntProperty("simpleInt");
simple.addLongProperty("simpleLong");
simple.addFloatProperty("simpleFloat");
simple.addDoubleProperty("simpleDouble");
simple.addStringProperty("simpleString");
simple.addByteArrayProperty("simpleByteArray");
//生成一个ContentProvider内容提供器,供其他程序访问数据
simple.addContentProvider().readOnly();
查询就是返回符合一定条件的实体。可使用原始的SQL语句执行查询;或是更好的方式,使用greenDAO中QueryBuilder的API。查询支持懒加载,当操作较大的结果集时,便可节约内存、提高性能。
举例:查询所有名为“Joe”的用户,且按姓排序。
List joes = userDao.queryBuilder()
.where(Properties.FirstName.eq("Joe"))
.orderAsc(Properties.LastName)
.list();
嵌套条件的例子:获取名为“Joe”出生在1970年10月份或1970年之后的用户。假如用户的生日分成年月日三个字段,这样便可换一种方式来表示上面的查询:名字是“Joe” AND (生日年份大于但不包括1970 OR(生日年份是1970 AND 月份大于等于10))。
QueryBuilder qb = userDao.queryBuilder();
qb.where(Properties.FirstName.eq("Joe"),
qb.or(Properties.YearOfBirth.gt(1970),
qb.and(Properties.YearOfBirth.eq(1970), Properties.MonthOfBirth.ge(10))));
List youngJoes = qb.list();
**(注意上面的括号,为了引出ge判断条件大于等于)
GreenDAO的Properties字段属性查询条件全部定义在了一个de.greenrobot.dao.Property类里面,详情请参照该类里面方法说明。
QueryBuilder的查询判断全部定义在一个de.greenrobot.dao.query.QueryBuilder类里面,详情请参照该类里面方法说明。
Query类代表着一个查询,可被执行多次。但使用QueryBuilder的方法之一(如list())获取一个结果时,QueryBuilder内部就是使用Query类。如果要多次执行相同的请求,可调用QueryBulder的build()方法创建一个查询而非执行它。
greenDAO同时支持获取单个结果(0或者1个结果)和结果列表。若期待获取一个结果可以调用Query(或QueryBulder)的unique(),这将返回一个结果或匹配不到返回null。若不允许返回nul,可调用uniqueOrThrow(),它将保证返回一个非null实体(否则会抛出一个DaoException)。
若期待返回多个结果,可以调用下面的list…方法:
list() 所有实体载入内存,以ArrayList形式返回,使用最简单。
listLazy() 实体按需加载到内存。当列表中的其中一个元素第一次被访问,它会被加载并缓存备将来使用。使用完必须关闭。
listLazyUncached() 一个“虚拟”的实体列表:任何访问列表中的元素都会从数据库中读取。使用完必须关闭。
listIterator() 可迭代访问结果集,按需加载数据,数据不缓存。使用完必须关闭。
方法listLazy,listLazyUncached和 listIterator需使用greenDAO的LazyList类。LazyList持有一个数据库游标,可按需加载数据。这也是为什么必须确保关闭懒加载列表和迭代器(通常使用try/finally包裹)。listLazy()的懒加载列表和listIterator()懒加载迭代器,在所有元素被访为或遍历后自动关闭游标。但是,还是必须调用close()方法,防止list的执行过早结束。
通过QueryBuilder创建一个Query,Query对象可以在一次查询结束后重新使用。相比创建新的Query对象,这样更加高效。如果查询参数没有改变,可再次调用list/unique方法。如果参数改变,则必须调用setParameter方法修改相应的参数。参数的索引地址从0开始。而索引为参数添加到QueryBuilder的顺序。
下面的例子使用一个查询对象,获取以“Joe”为名,出生于1970年的用户:
Query query = userDao.queryBuilder().where(
Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970))
.build();
List joesOf1970 = query.list();
使用该查询对象,可搜索“Marias”生于1977年:
query.setParameter(0, "Maria");
query.setParameter(1, 1977);
List mariasOf1977 = query.list();
多线程中使用查询,必须调用Query的forCurrentThread()获取当前线程的查询实例。从greenDAO1.3开始,Query对象实例绑定到创建它的线程。这样便可安全的设置Query对象的参数,不受其他线程影响。如果其他线程试图设置参数或执行查询,将抛出异常,这样便无需使用同步语句。实际上我们应该避免加锁,因为在并发处理使用了相同的查询对象,容易导致死锁。为完全避免潜在的死锁,greenDAO1.3引入方法forCurentThread(),返回一个本地线程的Query对象,可以被当前线程安全使用。每次forCurrentThread()方法被调用,所有参数将被设置成该查询被其builder创建时的参数。
有两种方法执行原始SQL语句,获取实体结果集。最好的方式是使用QueryBuilder和WhereCondition.StringCondition。可传入任何SQL片段到WHERE字句。如下:
Query query = userDao.queryBuilder().where(
new StringCondition("_ID IN " +
"(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)").build();
当QueryBuilder的功能未能符合需求时,可使用queryRaw或queryRawCreate方法。你可传入一个原始语句,它会被添加到SELECT和实体字段后。用这种方式可以编写任何WHERE和ORDER BY字句去查询需要的实体集。实体表可以使用别名“T”来引用。
下面的例子使用联合查询检索所在组为“admin”的所有用。
Query query = userDao.queryRawCreate(", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin");
注意:可用生成的常量表示表名和字段名。这是推荐的做法,避免编写错误。在一个实体的DAO中,TABLENAME表示数据库的表名,其内部类Properties则有所有属性的常量。
删除实体的基类是de.greenrobot.dao.AbstractDao,里面提供了删除的api
public void deleteAll() {
// String sql = SqlUtils.createSqlDelete(config.tablename, null);
// db.execSQL(sql);
db.execSQL("DELETE FROM '" + config.tablename + "'");
if (identityScope != null) {
identityScope.clear();
}
}
/** Deletes the given entity from the database. Currently, only single value PK entities are supported. */
public void delete(T entity) {
assertSinglePk();
K key = getKeyVerified(entity);
deleteByKey(key);
}
/** Deletes an entity with the given PK from the database. Currently, only single value PK entities are supported. */
public void deleteByKey(K key) {
……
}
这个类还提供了loadAll和insert方法
SQLite 数据库是支持事务的,事务的特性可以保证让某一系列的操 作要么全部完成,要么一个都不会完成。
GreenDAO也封装了SQLite的事务属性,如de.greenrobot.dao.AbstractDao类里(具体如何做SQLite事务的封装请参照源码):
/**
* Inserts the given entities in the database using a transaction.
*
* @param entities
* The entities to insert.
*/
public void insertInTx(Iterable<T> entities) {
insertInTx(entities, isEntityUpdateable());
}
如果查询结果没有返回你期待的,有两个静态标识可开启QueryBuilder的SQL和参数的日志输出:
QueryBuilder.LOG_SQL = true;
QueryBuilder.LOG_VALUES = true;
这样会输出SQL命令和调用相关build方法时传入的参数。
不过这个框架的本质是对sqlite数据库api的封装,提供了更简洁的api调用。相对使用android原生sqlite的优势有:
1、对于ORM关系型数据库,sqlite需要自己写sql语句来组织数据之间的关系,greendao提供了更加便捷的api为我们解决了。
2、实现了数据库查询list集合的缓存机制,这是sqlite所没有的。
3、解决了多线程查询中遇到的各种问题,避免了sqlite的加锁查询。
4、框架实现,让代码更加规范更加简洁。
GreenDAO框架给我们提供了在Android平台上很好的ORM框架设计思路,是一个非常值的学习的开源项目。