GreenDao
GreenDao是一个高效的数据库访问ORM框架,节省了自己编写SQL的时间,快速的增删查改等操作。
介绍就不多说,直接介绍重点吧!!!首先po一个github的地址:https://github.com/greenrobot/greenDAO
配置GreenDao
// In your root build.gradle file:
buildscript {
repositories {
jcenter()
mavenCentral() // add repository
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
}
}
// In your app projects build.gradle file:
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin
dependencies {
compile 'org.greenrobot:greendao:3.2.2' // add library
}
注意咯,一个是添加在工程的build.gradle,一个是添加到module的build.gradle文件中.
build.gradlel里面对greenDao进行配置。配置之后就搭建好了greenDao的环境,可以自动生成相关的类。
然后你需要配置greenDao的数据库版本号以及自动生成的包名的路径,当然路径可选择性的配置。
android{
...
}
greendao{
schemaVersion 2 // 数据库版本号
daoPackage 'com.doris.sample.greendao'//greenDao 自动生成的代码保存的包名
targetGenDir 'src/main/java' //自动生成的代码存储的路径,默认是 build/generated/source/greendao.
generateTests false //true的时候自动生成测试单元
targetGenDirTests: 测试单元的生成目录默认是 src/androidTest/java
}
接下来你定义自己的entity并且make project就可以开始对数据库进行操作啦。
下面对greenDao的相关知识点进行介绍:
注释
greenDAO 3 用注释去schemas 和实体类 entities.例子如下:
@Entity(nameInDb = "user_info",indexes = {
@Index(value = "name DESC", unique = true)
},)
public class User {
@Id
private Long id;
@Property(nameInDb = "USERNAME") @NotNull
private String name;
@Transient
private int tempUsageCount; // not persisted
// getters and setters for id and user ...
}
@Entity
将一个Java类转变成一个实体类。greenDao会根据这个生成对应的代码。PS: 必须是java类,kotlin不支持。
在Entity中我们可以配置许多信息,比如nameInDb
是声明了该表数据库中的表名。
indexes 用于建立索引,索引的应用场景可用于,当你的表有多个主键的时候,来标志一条数据的唯一性,配合unique。
当然上面两个只是我们常用的属性,还有几个其他属性,目前我还没有用到:
schema = "myschema", 当你有多个schema,用这个属性来告诉数据库当前entity属于哪个schema。
active = true,用于标志某个entity是否是active的,active的实体类有删改的方法。默认是fale, 为true的时候会自动生成下面的代码在entity里面:
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 128553479)
public void delete() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.delete(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 1942392019)
public void refresh() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.refresh(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 713229351)
public void update() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.update(this);
}
基本的属性:
@Id 标志主键
@Transient 表示不存储在数据库中
@NotNull 标志这个字段不能是null
@Property 如果定义了这个属性,那么nameInDb的值就是该列在数据表里面,该列的名称。上面的例子,username的值存储在数据表里面的USERNAME
那一列。
主键的限制
当前,entity必须有一个long或者Long的属性作为主键,但是有时候我们的主键不一定是long或者Long型的可能是string呀之类的,这个时候我们就可以定义索引属性并且注明独一无二。 如下:
@Index(name = "keyword", unique = true)
private String key;
name用于指明这个索引的列名,unique表示这个指是不可重复的。
@Unique 用于标志列的值的唯一性。
greenDao尽最大的可能的合理的安排每个属性的默认值,所以一般不需要去配置每一个选项。只需要配置你需要的就可以了。
当你编写好的entity之后,只需要点击Build-> make project就可以自动生成相关的代码了。
如果你改变了已经存在的entity记得rebuild工程保证旧的entity类被clean掉了。
记住不要随意修改注明了@Generated的代码,这样会导致报错,
Error:Execution failed for task ':app:greendao'.
> Constructor (see ExampleEntity:21) has been changed after generation.
Please either mark it with @Keep annotation instead of @Generated to keep it untouched,
or use @Generated (without hash) to allow to replace it.
解决这个的办法有两个:
- 将@Generated注释改回去,或者将自动生成的代码删掉,然后他会自动rebuild在下次build工程的时候。
- 将@Generated改成@Keep,这样greenDao将不会检查这段代码,但是这样可能会导致实体和greenDao其他的契合部分。另外,未来版本的greenDAO可能会在生成的方法中使用不同的代码。最好是不要修改这个,如果实在要修改,建议编写测试单元,测试一下确保不会有问题。
@Keep在新版本里面已经被淘汰了,如果当gradle检测到有@Keep会将他替换成@Transient!!!注意啦!!!
实体类建立好了,那么如何操作数据库,通过什么访问数据库呢,先来介绍一下greenDao的几个关键的类。
关键的几个类
DaoMaster
greenDao的入口,持有数据库(SQLiteDatabase)对象 并且 管理Schema的DAO类(不是对象)。持有静态的创建于删除表的方法。内部类OpenHelper以及DevOpenHelper实现了SQLiteOpenHelper,创建了数据库模式(Schema)。进行数据库连接。
DaoSession
管理特定模式的所有可用的DAO对象,通过getter方法可以获取到DAO对象。提供了增删查改实体的方法。
DAOs
全称Data access Objects,数据访问对象,对于每一个实体类,greenDao生成一个DAO,持有很多持久性的方法,例如 count, loadAll以及insertInTx。
Entities
持久化对象(与数据库对应的实体类),对应数据库里面的一行。
在用数据库之前首先需要初始化数据库,一般我们在Application里面进行数据库的数据化,并且只初始化一次。
// do this once, for example in your Application class
helper = new DaoMaster.DevOpenHelper(this, "notes-db", null);
db = helper.getWritableDatabase();
daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
然后要操作对应的对象的时候只需要获取到对应的Dao对象即可:
// do this in your activities/fragments to get hold of a DAO
noteDao = daoSession.getNoteDao();
Session
DaoSession
是greenDao重要的接口之一,提供了基本的实体类操作,Daos提供了更多的完整的操作。
获取Session
daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
请注意,数据库连接属于DaoMaster,因此多个会话引用相同的数据库连接。 因此,可以很快创建新的会话。 但是,每个会话都会分配内存,通常是实体的会话“缓存”。
Identity scope and session “cache”
如果有两个查询返回相同的数据库对象,那么您使用的Java对象有多少个:一个还是两个?它完全取决于身份范围。
greenDAO中的默认值(行为是可配置的)是多个查询返回对相同Java对象的引用。例如,从ID为42的USER表中加载一个User对象为这两个查询返回相同的Java对象。
这个副作用是某种实体“缓存”。如果一个实体对象仍然在内存中(greenDAO在这里使用弱引用),则该实体不会再构造。另外,greenDAO不执行数据库查询来更新实体值。相反,对象会从会话缓存中“立即”返回,这会比一个或两个数量级更快。
清除identity scope
清除整个session,没有缓存对象返回
daoSession.clear();
清除单个Dao的identity scope ,这样某个dao不会有缓存对象返回
noteDao = daoSession.getNoteDao();
noteDao.detachAll();
Queries
在GreenDao,你可以自己写原生的查询语句,也可以通过QueryBuilder
API来查询。
Query
用于查询的类
- QueryBuilder
SQL
的语法错误只有在run time
的时候才会提示,但是用greenDao
的QueryBuilder
可以在编译的时候就检测到错误。
查询范例:
List<User> joes = userDao.queryBuilder()
.where(Properties.FirstName.eq("Joe"))
.orderAsc(Properties.LastName)
.list();
用对应的Dao对对应的表进行查询操作,调用qureyBuilder
方法,where
是查询条件,可以有多个查询条件,用逗号分隔开来,如下:
List<User> joes = userDao.queryBuilder()
.where(Properties.FirstName.eq("Joe"), Properties.AGE.eq("10")
.orderAsc(Properties.LastName)
.list();
上面语句查询lastname是joe的并且年龄是10岁的人。
复杂的不是and连接的查询语句可以如下查询:
多个条件查询:
QueryBuilder<User> 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<User> youngJoes = qb.list();
上面语句应该如下解释
First name is "Joe" AND (year of birth is greater than 1970 OR (year of birth is 1970 AND month of birth is equal to or greater than 10))
即找出first name是joe的然后出生于1970年10以后的。
order
排序,我们可以对查询的结果进行排序。
orderAsc(依据的属性名称,可以有多个属性),正序 orderDesc 倒序
// order by last name
queryBuilder.orderAsc(Properties.LastName);
// in reverse
queryBuilder.orderDesc(Properties.LastName);
// order by last name and year of birth
queryBuilder.orderAsc(Properties.LastName).orderDesc(Properties.YearOfBirth);
greenDAO使用的默认排序规则是COLLATE NOCASE,尽管它可以使用stringOrderCollation()进行定制。 有关影响结果顺序的其他方法,请参见QueryBuilder类文档。
limit
当你根据条件查询,返回N条数据的时候,但是你只想要里面的前十个的时候,这个时候用limit
可以限制获取 n
条数据,不用for循环cursor。
limit
limit(int)
限制查询返回的条数。
需求千变万化的,有时候你需要的不是前面的n
条,而是从位置m
开始的n
条数据,这个时候就可以用offset
设置数据返回的偏移值。
offset(int)
设置返回数据的起始偏移值,得到offset开始的n条数据。必须要结合limit(int n)来使用
queryBuilder().where(Properties.YearOfBirth.gt(2001)).offset(3).limit(10)
上面例子是取出出生年份大于2001年的第3个开始的十个人。
查询条件总结
-
eq
:Properties.YearOfBirth.eq(2001):
等于 -
notEq
: 不等于 -
like
:模糊查询 记住模糊查询,string要用夹在%key%中间。
xxDao.queryBuilder().where(Properties.FirstName.like("%doris%")).list();
查询FristName包含doris的人。
-
BETWEEN ... AND ...
...和...之间。 -
IN(..., ..., ...)
在给出的value的范围内的符合项 -
gt
大于 -
ge
大于等于 -
lt
小于 -
le
小于等于 -
isNull
不是空的
查询有懒查询,也叫延迟查询吧,我觉得,就会你先执行了查询语句但是呢只有在你用的时候才会加载到内存,就类似于懒加载。
-
list()
不是懒加载,正常查询,查询结果立马加载到内存。 -
listLazy()
实体按需加载到内存中。 一旦列表中的元素第一次被访问,它将被加载并缓存以供将来使用。 必须关闭。 -
listLazyUncached()
一个“虚拟”实体列表:对列表元素的任何访问都会导致从数据库加载其数据。 必须关闭。 -
listIterator()
让我们通过按需加载数据(懒惰地)来遍历结果。 数据没有被缓存。 必须关闭。
greenDao还支持多线程查询以及重复使用Query对象,这个我还没用到,用到给大家再深入讲解一下哈!
原始查询
方法1:
Query<User> query = userDao.queryBuilder().where(
new StringCondition("_ID IN " +
"(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)")
).build();
方法2:
queryRaw
和queryRawCreate
Query<User> query = userDao.queryRawCreate(
", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin"
);
debug查询
QueryBuilder.LOG_SQL = true;
QueryBuilder.LOG_VALUES = true;
设置这两个属性就可以看到log、