GreenDao3.2的使用
一、简介
1.1 GreenDao
简介:GreenDao是一个简化数据库开发的ORM来(对象关系映射)源框架。
GreenDao官网,点击这里跳转
ORM优点:
1. 让业务代码访问对象,而不是数据库表;
2. 隐藏了面向对象的逻辑SQL查询详情;
3. 无需处理数据库实现。
GreenDao相对于原生API的优势:
1. 不需要手动拼sql;
2. 将数据库中的数据转换为相应的对象;
3. 实现级联查询。
1.2 为什么选择使用GreenDao
主流的ORM框架:OrmLite、SugarORM、LitePal、GreenDao。
GreenDao相对于其他ORM框架的优势:
1. 性能好、内存开销小;
2. 流行(遇到问题可以求助于别人);
3. 文档比较完善;
4. 使用简单;
5. 拓展性好。
二、gredle相关配置
2.1 主项目添加
在module的build.gredle 文件中的dependencies标签中添加:
dependencies {
compile'org.greenrobot:greendao:3.2.0'
}
2.2 添加插件
在root的build.gradle 文件添加:
dependencies {
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.0'
}
2.3 在module中应用插件
apply plugin: 'org.greenrobot.greendao'
2.4 greendao-generator
在多数情况下使用Gradle plugin就可以满足,但是一些高级特性目前仅由greendao-generator支持,例如multiple schemas。可以根据需求判断是否添加。
dependencies {
compile 'org.greenrobot:greendao-generator:3.2.0'
}
2.5 自定义路径
在module的build.gredle 文件根目录下添加:
greendao {
schemaVersion
targetGenDir ''
daoPackage ''
}
参数含义:
1. schemaVersion:指定数据库schema版本号,迁移等操作会用到。
2. targetGenDir:生成数据库文件的目录。
2. daoPackage:dao的包名,包名默认是entity所在的包。
例如:
三、实体类生成
3.1 创建一个实体类
常用注解:
一:实体注解
@Entity:表明这个实体类会在数据库中生成一个与之相对应的表。
- nameInDb:可以自定义表名,表名该实体对应数据库中的那张表,默认为实体类名。
- indexes:定义索引,这里可跨越多个列。
- createInDb:如果是有多个实体都关联这个表,可以把多余的实体里面设置为false避免重复创建(默认是true)。
- schema:一个项目中有多个schema时,标明要让这个dao属于哪个schema。
- active:是否应该生成更新/删除/刷新方法。如果Entity定义了 @ToOne 或 @ToMany关系,那么独立于该值是有效的。意为是否支持实体类之间update,refresh,delete等操作。
二:基础属性注解
1. @Id:对应数据表中的主键,是一条数据的唯一标识。如果实体没有声明主键,默认创建创建Long类型主键"_id"自增。使用Long类型主键时可以通过@Id(autoincrement = true)设置为自增。
2. @Property(nameInDb = "USER_NAME" ):可以自定义字段名,注意外键不能使用该属性。表名这个属性对应数据表中的 USER_NAME 字段。
3. @NotNull:该属性值不能为空。
4. @Transient:该属性不会被存入数据库中。
5. @Unique:表明该属性在数据库中只能有唯一值。
6. @Index:创建一个索引。通过name设置索引别名,也可以通过unique给索引添加约束。
7. @Convert:指定一个PropertyConverter用于支持自定义类型(没用过)。
三:关系注解
1. @ToOne:定义自己与一个实体对象的关系。
2. @ToMany:定义自己与多个实体对象的关系。@ToMany的属性referencedJoinProperty,类似于外键约束。
3. @JoinProperty:对于更复杂的关系,可以使用这个注解标明目标属性的源属性。
4. @JoinEntity:如果你在做多对多的关系,有其他的表或实体参与,可以给目标属性添加这个额外的注解。
5. @OrderBy:指定{@ToMany}关系的相关集合的排序。**(propertyA, propertyB)默认为按主键ASC排序**
四:派生注解
1. @Generated:这个是build后greendao自动生成的,这个注解理解为防止重复,每一块代码生成后会加个hash作为标记。 官方不建议你去碰这些代码,改动会导致里面代码与hash值不符。
3.2 Make module
build -> Make module
会在build.gredle配置的路径(目录2.5)下创建一下文件,实体类也会自动生成一些代码:
四、初始化
4.1 初始化
4.2 拿到表对应的Dao对象
五、简单使用
5.1 增
5.1.1 inser()
public long insert(T entity) {}
说明:将实体数据插入到相应的表中,返回:新插入实体的行ID(默认从1开始)。
5.1.2 insertInTx()
public void insertInTx(T... entities) {}
public void insertInTx(Iterable<T> entities) {}
public void insertInTx(Iterable<T> entities, boolean setPrimaryKey) {}
说明:使用事务将给定实体插入数据库中。批量添加。
5.1.3 insertOrReplace()
public long insertOrReplace(T entity) {}
说明:将实体数据插入或替换到相应的表中(以主键为依据,当主键重复时替换),返回新插入实体的行ID。
5.1.4 insertOrReplaceInTx()
public void insertOrReplaceInTx(T... entities) {}
public void insertOrReplaceInTx(Iterable<T> entities) {}
public void insertOrReplaceInTx(Iterable<T> entities, boolean setPrimaryKey) {}
说明:使用事务插入或替换数据库中给定的实体(以主键为依据,当主键重复时替换)。批量添加。
5.1.5 save()
public void save(T entity) {}
说明:类似于insertOrReplace()方法,但比它更有效率,因为当key已经存在时,不需要查询直接更新。建议使用此方法。
5.1.6 insertWithoutSettingPk()
public long insertWithoutSettingPk(T entity) {}
说明:将一个实体插入到相应的表中,而不需要设置主键属性。返回:新插入实体的行ID。注意:这可能会更快,但实体不应该再使用了。实体也不会附加到标识作用域。仅对主键为Long类型自增有效,String类型主键会Error。
5.2 删
5.2.1 deleteAll()
public void deleteAll() {}
说明:删除相应表的全部数据(清空相应表)。
5.2.2 deleteByKey
public void deleteByKey(K key) {}
说明:删除给定PK的实体。目前,仅支持惟一PK实体。
5.2.3 deleteByKeyInTx
public void deleteByKeyInTx(K... keys) {}
public void deleteByKeyInTx(Iterable<K> keys) {}
说明:使用事务删除数据库中给定键的所有实体。批量删除。
5.2.4 delete()
public void delete(T entity) {}
说明:删除给定的实体。目前,仅支持惟一PK实体。entity的id属性必须有值,否则报错。其实就是删除与entity主键值相同的数据,entity的其他数据值与表中数据值不一致时,也会删除。
5.2.5 deleteInTx()
public void deleteInTx(T... entities) {}
public void deleteInTx(Iterable<T> entities) {}
说明:使用事务删除数据库中给定的实体。批量删除。每个entity的id属性必须有值,否则报错。其实就是删除与entity主键值相同的数据,entity的其他数据值与表中数据值不一致时,也会删除。
5.3 改
5.3.1 update()
public void update(T entity) {}
说明:更新给定的实体。entity的id属性必须有值,否则报错。若entity的id值表中不存在时,不会报错。
5.3.2 updateInTx()
public void updateInTx(T... entities) {}
public void updateInTx(Iterable<T> entities) {}
说明:使用事务更新数据库中给定的实体。批量更新。每个entity的id属性必须有值,否则报错。若entity的id值表中不存在时,不会报错。
5.4 查
5.4.1 load()
public T load(K key) {}
说明:加载给定PK的实体。传入:key or null。返回:该实体 或 null。
5.4.2 loadByRowId()
public T loadByRowId(long rowId) {}
说明:加载给定RowId的实体。传入:key or null。返回:该实体 或 null。
5.4.3 loadAll()
public List<T> loadAll() {}
说明:从数据库加载所有可用的实体。
5.4.4 unique()
public T unique() {}
说明:返回一个或者零个结果。
5.4.5 uniqueOrThrow()
public T uniqueOrThrow() {}
说明:返回非空的结果,否则抛出异常。
5.5 其他
5.5.1 查看QueryBuilder拼接的SQL和参数信息
如果查询没有返回预期的结果,可以使用GreenDao提供的两个静态Flag打印QueryBuilder拼接的SQL和参数信息。
QueryBuilder.LOG_SQL = true;//打印SQL标志
QueryBuilder.LOG_VALUES = true;//打印参数标志
5.5.2 detach
5.5.2.1 detach()
public boolean detach(T entity) {}
说明:将一个实体从会话中拆分。后续查询结果不会返回此对象。
5.5.2.2 detachAll()
public void detachAll() {}
说明:将所有实体(T型)从身份范围(会话)中拆分。后续的查询结果不会返回任何以前加载的对象。
5.5.3 refresh()
public void refresh(T entity) {}
说明:通过从数据库重新加载重置该实体的所有本地更改属性。
六、高级查询
6.1 queryBuilder()
示例:
6.1.1 查询条件
- between(Object value1, Object value2): BETWEEN … AND …
- eq(Object value): equal (‘=’)
- notEq(Object value): not equal (‘<>’)
- gt(Object value): than (‘>’)
- lt(Object value): less than (‘<’)
- ge(Object value): greater or equal (‘>=’)
- le(Object value): less or equal (‘<=’)
- like(String value): LIKE
- isNotNull(): IS NOT NULL
- isNull(): IS NULL
- in(Object… inValues): IN (…, …, …)
- notIn(Object… notInValues): NOT IN (…, …, …)
- in(Collection< ?> inValues): IN (…, …, …)
- notIn(Collection< ?> notInValues): NOT IN (…, …, …)
6.1.2 Query的使用
当多次使用到查询的时候,更加高效的方法是新建一个 Query 对象。然后根据需要更改相应的查询参数。
示例:
public Query<T> setParameter(int index, String parameter) {}
public Query<T> setParameter(int index, Date parameter) {}
public Query<T> setParameter(int index, Boolean parameter) {}
说明:index 从 0 开始,代表where条件的下标;parameter代表需要修改的相应参数。
6.1.3 生成结果集方法
6.1.3.1 list()
public List<T> list() {}
说明:执行查询并将返回一个包含所有entity的list为结果,直接加载在内存中。
6.1.3.2 listLazy()
public LazyList<T> listLazy() {}
说明:用到懒加载技术。当真正用到数据时(访问entity的属性时),才会查询数据库。多用于多表级联查询。使用完必须关闭游标。
关闭游标:
6.1.3.3 listLazyUncached()
public LazyList<T> listLazyUncached() {}
说明:也实现了懒加载技术,但是返回结果list没有保存在内存中,没法复用,每次都会向数据库查询真正的数据。使用完必须关闭游标。
6.1.3.4 listIterator()
public CloseableListIterator<T> listIterator() {}
说明:执行查询并将结果作为列表迭代器返回;确保关闭它以关闭底层游标。一旦迭代器完全迭代,游标就会关闭。
6.2 原生SQL查询
如果GreenDao的查询条件不能满足,可以使用此方法定制自己的查询语句。
6.2.1 queryBuilder()
6.2.2 queryRawCreate()
public Query<T> queryRawCreate(String where, Object... selectionArg) {}
说明:基于给定的原始SQL创建一个可重复的{查询}对象,可以在这里传递任何WHERE子句和参数。
6.2.3 queryRaw()
public List<T> queryRaw(String where, String... selectionArg) {
说明:一个原始样式查询,可以在这里传递任何WHERE子句和参数。
6.2.4 queryRawCreateListArgs()
public Query<T> queryRawCreateListArgs(String where, Collection<Object> selectionArg) {}
说明:基于给定的原始SQL创建一个可重复的{查询}对象,您可以在这里传递任何WHERE子句和参数。
6.3 多线程查询
GreenDao多线程查询机制:每一个线程中都有一个查询对象,如果查询对象的创建线程和调用线程不一致,则抛出异常,通过这种机制来保证多线程查询的正确性。
示例:
注意:query.forCurrentThread()方法返回的Query对象的所有参数都会重置为QueryBuilder指定的初始值。在上述示例中指定初始值limit(3),然后更改为limit(5),query.forCurrentThread()方法会将所有参数重置为指定的初始值,所以为limit(3)。
运行结果:
6.4 1:1 查询
示例:现有两张表:作者表和文章表,文章表中有一列authorId对应作者表的id。希望可以通过文章的id查询作者信息。
作者表:
文章表:
查询id=1的文章的作者的信息:
查询结果:
6.5 1:N 查询
示例:现有两张表:作者表和文章表,文章表中有一列authorId对应作者表的id。希望可以通过作者id查询所有的文章信息。
6.5.1 实现方式一
作者表:
文章表:
查询id=1的作者的所有文章信息:
查询结果:
6.5.2 实现方式二
作者表:
文章表:
@ToMany()表明当前作者表的id对应章表的authorId。查询方式代码与方式一类似。
七、RxDao
导包:
compile 'io.reactivex:rxjava:1.3.0'
compile 'io.reactivex:rxandroid:1.2.1'
注意:目前仅支持RxJava1版本,不支持RxJava2版本。
DaoSession:
- RxTransaction rx():返回在IO线程发射事件的 Observables
- RxTransaction rxPlain():返回没有设置无线程调度的 Observables
Dao:
- RxDao<T, K> rx()
- RxDao<T, K> rxPlain()
QueryBuilder:
- RxQuery<T> rx()
- RxQuery<T> rxPlain()
备注:rxPlain形式没有设置调度线程,可根据需要自行指定工作线程。
7.1 Dao
7.1.1 初始化
7.1.2 增
注意:会把给定的实体在插入后发射给订阅者。(要插入的实体没有指定id(Entity设置了主键自增),返回实体有id,说明返回的是插入后的实体。其他方法类似。)
7.1.3 删
备注:其他方法(例如 save() )使用方式类似。
7.2 RxQuery
注意:此为异步线程,多处调用会导致每个线程开启事务,当其中一个线程关闭事务的时候其他线程不知道,导致死锁。
八、数据库加密
说明:
- 使用getEncryptedReadableDb()和getEncryptedWritableDb()获取加密的数据库;
- 256位AES加密,会提升APK的大小;
- Robolectric(一种单元测试框架)测试时,须使用非加密数据库;
导包:
compile 'net.zetetic:android-database-sqlcipher:3.5.7@aar'
使用:
注意:必须使用相同的秘钥拿到Session才能将加密DB中的数据取出来,加密过的数据库文件使用工具打开也只能看到表结构,看不到表中的数据。
九、数据库版本迭代
DaoMaster.DevOpenHelper数据库升级时会删除所有表,仅适用于开发期。实际中需要继承DaoMaster.OpenHelper实现onUpgrade()方法。
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
for (int j = oldVersion + 1; j <= newVersion; j++) {
switch (j) {
case 2:
break;
case 3:
break;
default:
break;
}
}
}
升级辅助库 GreenDaoUpgradeHelper,通过 MigrationHelper 在删表重建的过程中,使用临时表保存数据并还原。gitHub地址,点击这里跳转