博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 数据库 —— greeDAO
阅读量:4296 次
发布时间:2019-05-27

本文共 10506 字,大约阅读时间需要 35 分钟。

数据存储方式

一般文章中介绍数据存储有这么几种:

  • 文件

  • SharedPreferences

  • 数据库

  • 网络

  • ContentProvider

其实,在内存存储也可以算是一种存储,比如,有些时候我们用 static 变量存储一些共享数据,只不过与上面的数据不用,上面的是持久化数据存储,但是也是一种数据存储方式,需要根据需求来决定使用哪种方式。加上内存存储构成三级缓存策略,

内存—>本地—>网络,不同级别的数据一般情况下,使用频率也是逐级降低的,这也是一种规律,因为对于移动端来说,提高用户体验的其中一点也是加载速度快,那么当然从内存中拿出数据来效率更高,但是不可能所有数据都能放在内存中,毕竟内存有限,而且有些数据也是需要长久记录下来的,设备重启或者应用重启后,保存在进程中的数据也就释放掉了。

下面说一说持久化存储的特点:

文件

文件,这种类型的数据一般都是文件格式,比如图片,word,text等但是大小和数量也不能太多,毕竟移动设备的存储空间有限。另外这种数据一般官方的建议是存储在外部私有存储空间,因为内部存储空间有限,对于外部存储空间,如果存在公有空间,则删除应用时文件不会被删除,如果保存在外部私有空间,删除应用时数据也会一并被删除,这样也能够减少一些用户喷来的口水!

SP

对于 SP 来说,一般也比较简单与方便,常常我们都是拿 SP 工具类来进行数据存储的,对于 SP 存储的数据,也是少量的,但是同为本地数据存储,有哪些特点,换句话说,在哪些场景下使用 SP ?

  • 只支持存储Java基础数据类型(Boolean、Int、Float、String、Long等)不支持自定义数据类型。

  • 本质是一种Map,通过键值对的形式进行数据存储。

  • 不支持查找功能。

从这几个特点中可以看出,实际上用 SP 存储一些基本的数据类型,虽然用你也可以将数据放在本地文件中,但是没有 SP 方便,SP 可以根据 key 直接取出。同样,SP 是放在内存存储空间的,数据量也是相对较小的。

数据库

很明显,数据库就是要解决 SP 不能存储自定义对象的烦恼。SQL 数据库叫做“结构化查询语言”,也就是说是用来存储结构化数据的,这里可以理解为对象,所以数据库一般是关系型数据库。对于数据存储的数据也可以存储到文件中,只不过我们需要将对象数据序列化,存储到文件中,然后读取的时候在反序列化,这对于开发者来说,很麻烦数据库能够很好地解决这个问题。开发者只管存储就行,不需要关心序列化和反序列化的过程。

对于移动端的数据库,一般都是轻量级的,像安卓端的 Sqlite,毕竟是移动端,不能搞得像 PC 上那么大。对于移动端的数据库一般也有以下几个特点

  • 自定义数据类型,一般是对象。

  • 存储在本地的内部存储空间,数据也不会太大

  • 支持查找。

数据库现在也有很多优秀的开源框架可以使用,不同的框架也有不同的特点,那么对于开发者来说如何选择?其实无非也就这么几点:

  • 满足性能要求,比如速度快,数据量大时,稳定

  • 简单易操作,能不写代码最好~~

  • 轻量级,引入的包很大的话,也会对APK的大小有影响,以及初始化的速度等

greenDao 介绍

为啥本篇主要来说一说 greenDao 呢?原因很简答,之前没用过,当然来尝试一下了。

原生的 sqlite 就不说了,应用大家都不会用原生的数据库,如果原生的数据库好用的话,估计也不会出现各种开源框架了!

对于数据库,特别是移动端的,涉及的操作不会很多,也就是增删改查,不熟悉的可以在 上复习一下。

SELECT - 从数据库表中获取数据UPDATE - 更新数据库表中的数据DELETE - 从数据库表中删除数据INSERT INTO - 向数据库表中插入数据

大神们喜欢使用原始的 SQL 语句,对于我这种小菜鸟,还是喜欢更简单的框架,所以对于我来说,好的数据库框架,一般是越无脑越好,性能越高越好,怎么平衡它?看你自己了。

之前使用 LiteOrm,这个框架比较简单,有兴趣的可以看看这篇文章-。至于性能和 greenDAO 对于,没有亲子测过(主要是不会测~),可以看看 这篇文章。

greenDAO,官网链接 。

LiteOrm,官网链接 。

对月 greenDAO,官方是这么说它的特点的:

(1) Rock solid: greenDAO has been around since 2011 and is used by countless famous apps     非常稳定,自从 2011 年开始就被无数有名气的 App 使用(2) Super simple: concise and straight-forward API, in V3 with annotations    超级简单(倒是觉得没有 LiteOrm简单),有简单的使用 API,在 v3 版本中引入注解(3) Small: The library is <150K and it's just plain Java jar (no CPU dependent native parts)    很小,库是于 150 K 的 jar 包(不含有依赖 CPU 的本地代码部分,指的是 so库)(4) Fast: Probably the fastest ORM for Android, driven by intelligent code generation    速度快,可能是 android 上最快的 ORM,可以自动生成代码(5) Safe and expressive query API: QueryBuilder uses property constants to avoid typos    安全和容易记忆的查询 API:QueryBuilder 使用合适的常量来避免拼写错误(6) Powerful joins: query across entities and even chain joins for complex relations    有强大的联合查询:支持实体间的交叉查询,以及支持复杂的链式查询(7) Flexible property types: use custom classes or enums to represent data in your entity    拥有更灵活的类型,可以使用类类型或者枚举,来表示你的实体类(8) Encryption: supports SQLCipher encrypted databases    可以加密:支持 SQLCipher 加密数据库

好,看它吹完牛和我唠叨完,我们还是实际使用一下,来感受感受!

greenDAO 使用

官方也是给出了

配置

工程目录下 build.gradle 添加如下配置:

buildscript {    repositories {        google()        jcenter()    }    dependencies {        classpath 'com.android.tools.build:gradle:3.1.0'        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin    }}

在 app 的 build.gradle 下配置:

apply plugin: 'com.android.application'apply plugin: 'org.greenrobot.greendao' // apply pluginandroid {    ...}dependencies {    ...    implementation 'org.greenrobot:greendao:3.2.2'}

新建实体类

@Entitypublic class Note {
@Id private Long id; private String name; private int age; //下面省去了 setter/getter}

常用注解:

  1. @Entity – 实体注解
public @interface Entity {
/** * 在数据库中表的名称,默认为实体的类名 */ String nameInDb() default ""; /** * 定义索引,可以跨越多个列(默认为实体类成员变量的个数) */ Index[] indexes() default {}; /** * 标记创建数据库表 * 如果是有多个实体都关联这个表,可以把多余的实体里面设置为false避免重复创建(默认是true) */ boolean createInDb() default true; /** * 告知GreenDao当前实体属于哪个schema */ String schema() default "default"; /** * 实体活动状体标志位(默认为false) * 若设置为true,实体有更新、删除和刷新方法 */ boolean active() default false; }
  1. @Generated 派生属性

@Generated 这个是build后greendao自动生成的,这个注解理解为防止重复,每一块代码生成后会加个hash作为标记。 官方不建议你去碰这些代码,改动会导致里面代码与hash值不符。

@Generated(hash = 1272611929)    public Note() {    }    public Note(Long id) {        this.id = id;    }    @Generated(hash = 1686394253)    public Note(Long id, @NotNull String text, String comment, java.util.Date date, NoteType type) {        this.id = id;        this.text = text;        this.comment = comment;        this.date = date;        this.type = type;    }
  1. @NotNull – 设置表中当前列的值不可为空

  2. @Convert– 指定自定义类型,将自定义的数据类型,转换为数据库中所存储列的值的类型

@Convert(converter = NoteTypeConverter.class, columnType = String.class)    private NoteType type;
  1. @Id– 主键 Long型,可以通过@Id(autoincrement = true)设置自增长。通过这个注解标记的字段必须是Long,数据库中表示它就是主键,并且默认是自增的。
@Id    private Long id;

6.索引属性-两种方法

(1)@Index– 使用@Index作为一个属性来创建一个索引;

@Index 通过这个字段建立索引

@Unique 添加唯一约束,上面的括号里unique=true作用相同

@Entitypublic class User {
@Id private Long id; @Index(unique = true) private String name;}@Entitypublic class User {
@Id private Long id; @Unique private String name;}

(2)定义多列索引(@link Entity#indexes())

通过逗号间隔创建表的属性索引,例如 “propertyA,propertyB,propertyC” ,

若要指定排序, 需在列明以后添加 ASC(升序) 或者DESC(降序) , 例如 “propertyA DESC, propertyB ASC” ,只有实体类中使用 {@link Entity#indexes()} 才可设置

@Entity(indexes = {        @Index(value = "text, date DESC", unique = true)})public class Note {
...}
  1. 关系注解
    (1)一对一
@Entitypublic class Order {
@Id private Long id; private long customerId; @ToOne(joinProperty = "customerId") private Customer customer;}@Entitypublic class Customer {
@Id private Long id;}

@ToOne 是将自己的一个属性与另一个表建立关联,如果不设置joinProperty,在Customer表中会自动创建外键,值是自动增加的。

(2)一对多

public @interface ToMany {
/** * 目标实体持有源实体的名称 * 如果没设置,否则有 {@link JoinProperty} or {@link JoinEntity} 指定 */ String referencedJoinProperty() default ""; /** * 将源表列索引->目标列 * 如果没设置,否则有 {@link JoinProperty} or {@link JoinEntity} 指定 */ JoinProperty[] joinProperties() default {}; }

上面的可能不是很好理解,其中也涉及了其他注解,@JoinProperty@JoinEntity

,意思是如果设置了 referencedJoinProperty 作为另一个表的外键,可以不设置 @JoinProperty@JoinEntity,否则就要设置这两个注解。举个例子。

方式一:

@Entitypublic class User {
@Id private Long id; @ToMany(referencedJoinProperty = "ownerId") private List
ownedSites;}@Entitypublic class Site {
@Id private Long id; private long ownerId;}

一个 User 中可能有多个 Site ,那么对于 Site 和 User 联系起来是通过 ownerId

方式二:

如果不指定 ownerId,通过 @JoinProperty

@Entitypublic class User {
@Id private Long id; @Unique private String authorTag; @ToMany(joinProperties = { @JoinProperty(name = "authorTag", referencedName = "ownerTag") }) private List
ownedSites;}@Entitypublic class Site {
@Id private Long id; @NotNull private String ownerTag;}

从上面看到通过 User 中的 authorTag 和 Site 中的 ownerTag 联系起来。

方式三:

(3) 多对多

@Entitypublic class Site {
@Id private Long id; @ToMany @JoinEntity( entity = JoinSiteToUser.class, sourceProperty = "siteId", targetProperty = "userId" ) private List
authors;}@Entitypublic class JoinSiteToUser {
@Id private Long id; private Long siteId; private Long userId;}@Entitypublic class User {
@Id private Long id;}

单独定义一个关系类 JoinSiteToUser ,通过该类将 Site 和 User 联系起来。

  1. @OrderBy– 指定排序

一般也是使用在 @toMany 中.

public @interface OrderBy {
/** * 通过逗号间隔创建表的属性索引,例如 “propertyA,propertyB,propertyC” * 若要指定排序, 需在列明以后添加 ASC(升序) 或者DESC(降序) , 例如 "propertyA DESC, propertyB ASC" * 默认按升序排序 * 若不设置默认根据主键排序 */ String value() default ""; }

9.@Property– 设置数据库中的列名,默认是的使用字段名

举例:@Property (nameInDb=”name”)

public @interface Property {
/** * 默认是的使用字段名 */ String nameInDb() default ""; }
  1. @Keep– 注解的代码段在GreenDao下次运行时保持不变
(1)注解实体类:默认禁止修改此类(2)注解其他代码段,默认禁止修改注解的代码段
  1. @Transient– 添加次标记之后不会生成数据库表的列

初始化

编写完实体类之后,进行编译,会生成 DaoMaster,DaoSession,和一个实体 DAO类,如实体类是 User,则对应的是 UseDao 类。

然后在 Application 中初始化,看到代码中加了加密的设置。greenDao 允许加密, 若要使用加密,需要在 build.gradle 中加入以下依赖。

// This is only needed if you want to use encrypted databases    implementation 'net.zetetic:android-database-sqlcipher:3.5.6'

Application 中初始化

public class MyApplication extends Application {
/** A flag to show how easily you can switch from standard SQLite to the encrypted SQLCipher. */ public static final boolean ENCRYPTED = false; private DaoSession daoSession; @Override public void onCreate() { super.onCreate(); DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, ENCRYPTED ? "notes-db-encrypted" : "notes-db"); Database db = ENCRYPTED ? helper.getEncryptedWritableDb("super-secret") : helper.getWritableDb(); daoSession = new DaoMaster(db).newSession(); } public DaoSession getDaoSession() { return daoSession; }}

DaoMaster:使用greenDAO的切入点。 DaoMaster保存数据库对象(SQLiteDatabase)并管理特定模式的DAO类(而不是对象)。 它有静态方法来创建表或删除它们。 它的内部类OpenHelper和DevOpenHelper都是SQLiteOpenHelper的实现,用来在SQLite数据库中创建模式。

DaoSession:管理特定模式的所有可用DAO对象,你可以使用其中一个的getter方法获取DAO对象。 DaoSession还为实体提供了一些通用的持久性方法,如插入,加载,更新,刷新和删除。 最后,DaoSession对象也跟踪identity scope。

DAO:数据访问对象(DAO),用于实体的持久化和查询。 对于每个实体,greenDAO会生成一个DAO。 它比DaoSession拥有更多的持久化方法,例如:count,loadAll和insertInTx。

greenDAO Gradle插件

greendao {    targetGenDir 'src/main/java'    daoPackage 'com.XXXX.dao.db'}

schemaVersion:数据库模式的当前版本。 这由* OpenHelpers类用于在模式版本之间迁移。 如果更改实体/数据库模式,则必须增加此值。 默认值为1。

daoPackage:生成的DAO,DaoMaster和DaoSession的包名称。 默认为源实体的包名称。

targetGenDir:生成的源码应存储在的位置。 默认为生成目录(build / generated / source / greendao)中生成的源文件夹。

generateTests:设置为true以自动生成单元测试。

targetGenDirTests:生成的单元测试应存储在的基本目录。 默认为src / androidTest / java。

增删改查

  1. 查询
DaoSession daoSession = ((MyApplication) getApplication()).getDaoSession();    userDao = daoSession.getUserDao();    ...    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();
  1. 添加
User user = new User();    user.setName("Nick");    user.setAge(25);    user.setId(12);    userDao.insert(user);
  1. 更新
user = userLists.get(10);    user.setName(Ralf);    user.setAge(29);    userDao.update(user);
  1. 删除
Long userId = user.getId();    userDao.deleteByKey(userId);

以上就是 greenDao 的基本介绍,数据库也是很复杂的一部分,但是对于移动端来说,一般会一些基本的操作大部分场景都能够满足,如果需要更多操作可以参考官方的说明文档 .

另外需要关注的是,greenrobot 又出了 ObjectBox,使用更加单,也是 greenrobot 大力推荐的,后面会做一下介绍。下一篇会对 greenDao 进行封装使用,然后自己设计稍微复杂的表进行实践一下,也不能总是对着一张表增删改查,要不有点那啥。。。

好,就到这里,敬请期待!

转载地址:http://zidws.baihongyu.com/

你可能感兴趣的文章
Xcode 工程文件打开不出来, cannot be opened because the project file cannot be parsed.
查看>>
点击button实现Storyboard中TabBar Controller的tab切换
查看>>
Xcode 的正确打开方式——Debugging
查看>>
打包app出现的一个问题
查看>>
iOS在Xcode6中怎么创建OC category文件
查看>>
Expanding User-Defined Runtime Attributes in Xcode with Objective-C
查看>>
iOS7 UITabBar自定义选中图片显示为默认蓝色的Bug
查看>>
提升UITableView性能-复杂页面的优化
查看>>
25 iOS App Performance Tips & Tricks
查看>>
那些好用的iOS开发工具
查看>>
iOS最佳实践
查看>>
使用CFStringTransform将汉字转换为拼音
查看>>
更轻量的 View Controllers
查看>>
Chisel-LLDB命令插件,让调试更Easy
查看>>
时间格式化hh:mm:ss和HH:mm:ss区别
查看>>
When to use Delegation, Notification, or Observation in iOS
查看>>
Objective-C Autorelease Pool 的实现原理
查看>>
编程语言大牛王垠:编程的智慧,带你少走弯路
查看>>
ios指令集以及基于指令集的app包压缩策略
查看>>
iOS开发者的福利 — — iOS9+Xcode7免越狱免证书直接调试
查看>>