1. 什么是greenDao
弄明白greenDao之前我們應(yīng)該先了解什么是ORM(Object Relation Mapping 即 對(duì)象關(guān)系映射)啊楚,說白了就是將面向?qū)ο缶幊陶Z(yǔ)言里的對(duì)象與數(shù)據(jù)庫(kù)關(guān)聯(lián)起來的一種技術(shù)诫肠,而greenDao就是實(shí)現(xiàn)這種技術(shù)之一络它,所以說greenDao其實(shí)就是一種將java object 與SQLite Database關(guān)聯(lián)起來的橋梁,它們之間的關(guān)系 如下圖所示蔑水;
greenDao 啥箭,SQLite Database與Java Object對(duì)象之間的關(guān)系
2. 為什么要使用greenDao
greenDao可以說是當(dāng)今最流行,最高效而且還在迭代的關(guān)系型數(shù)據(jù)庫(kù)爹梁。而且greenDao3.0還支持RxJava操作右犹,greenDao如此受歡迎離不開以下幾點(diǎn):
存取速度快
每秒中可以操作數(shù)千個(gè)實(shí)體 下圖是幾種常見關(guān)系型數(shù)據(jù)庫(kù)性能比較;
幾種常用數(shù)據(jù)庫(kù)比較
支持?jǐn)?shù)據(jù)庫(kù)加密
支持android原生的數(shù)據(jù)庫(kù)SQLite姚垃,也支持SQLCipher(在SQLite基礎(chǔ)上加密型數(shù)據(jù)庫(kù))念链。
輕量級(jí)
greenDao的代碼庫(kù)僅僅100k大小
激活實(shí)體
處于激活狀態(tài)下的實(shí)體可以有更多操作方法
支持緩存
能夠?qū)⑹褂玫倪^的實(shí)體存在緩存中,下次使用時(shí)可以直接從緩存中取积糯,這樣可以使性能提高N個(gè)數(shù)量級(jí)
代碼自動(dòng)生成
greenDao 會(huì)根據(jù)modle類自動(dòng)生成實(shí)體類(entities)和Dao對(duì)象掂墓,并且Dao對(duì)象是根據(jù)entities類量身定做的并且一 一對(duì)應(yīng)。
3. 怎樣使用greenDao
3.1 入門
3.1.1 配置GreenDao
buildscript { repositories { mavenCentral() } dependencies { classpath 'org.greenrobot:greendao-gradle-plugin:3.2.0'//greenDao生產(chǎn)代碼插件 }apply plugin: 'org.greenrobot.greendao'//greendao插件dependencies { compile 'org.greenrobot:greendao:3.2.0'
配置數(shù)據(jù)庫(kù)信息
greendao {
//數(shù)據(jù)庫(kù)schema版本看成,也可以理解為數(shù)據(jù)庫(kù)版本號(hào)
schemaVersion 2
//設(shè)置DaoMaster 君编、DaoSession、Dao包名
daoPackage 'com.qhn.bhne.footprinting.db'
//設(shè)置DaoMaster 川慌、DaoSession吃嘿、Dao目錄
targetGenDir 'src/main/java'
//設(shè)置生成單元測(cè)試目錄
// targetGenDirTest
//設(shè)置自動(dòng)生成單元測(cè)試用例
// generateTests
}
到這里數(shù)據(jù)庫(kù)基本配置已經(jīng)完成偿荷,接下來讓我們一起來了解下greenDao的核心類該怎樣使用吧。
3.1.2 核心類介紹
greenDao核心類構(gòu)成
**DaoMaster: **
是GreenDao的入口也是greenDao頂級(jí)對(duì)象,對(duì)于一個(gè)指定的表單持有數(shù)據(jù)庫(kù)對(duì)象(SQLite數(shù)據(jù)庫(kù))并且能夠管理DAO類- 能夠創(chuàng)建表和刪除表
其內(nèi)部類OpenHelper 與DevOpenHelper是創(chuàng)建SQlite數(shù)據(jù)庫(kù)的SQLiteOpenHelper的具體實(shí)現(xiàn)
DaoSession:
對(duì)于一個(gè)指定的表單可以管理所有的Dao 對(duì)象唠椭。
也能夠?qū)?shí)體類執(zhí)行 insert ,load跳纳,update,refresh.delete操作。
DaoSession也能跟蹤 identity scope:即session查詢后的實(shí)體會(huì)存在緩存中贪嫂,并給該實(shí)體生成一個(gè)flag來追蹤該實(shí)體寺庄,下次再次查詢時(shí)會(huì)直接從緩存中取出來而不是從數(shù)據(jù)庫(kù)中取出來
DAOS
能夠持久訪問和查詢實(shí)體類
比起DaoSession有更多的持久化方法 count, loadAll,insertInt等等;
**Entities **
自動(dòng)生成的代碼力崇,一般情況下與javaBean對(duì)象的屬性一一對(duì)應(yīng)斗塘。
3.1.3 構(gòu)建Model類
Molde類需要用java類來定義并且可以通過GreenDao中的注釋來表明Model中的每個(gè)屬性在數(shù)據(jù)庫(kù)的中該如何定義;定義model類后點(diǎn)擊Make project選項(xiàng)GreenDao就會(huì)自動(dòng)生成DaoMaster,DaoSession,和DAOS類亮靴,生成的代碼將會(huì)保存在預(yù)先在budle gradle中設(shè)置的位置.
實(shí)體和注釋
GreenDao 通過注釋來定義表單與實(shí)體
@Entitypublic class User { @Id private Long id; private String name; @Transient private int tempUsageCount; // 沒有存入數(shù)據(jù)庫(kù)中}
@Entity
告訴GreenDao 該Bean類需要持久化馍盟。只有使用@Entity注釋的Bean類才能被dao類操作;
@Entity可以在不使用參數(shù)下使用,但是也可以給Entity配置參數(shù)
//如果該實(shí)體屬于多個(gè)表單茧吊,可以使用該參數(shù); schema = "myschema", // 該實(shí)體屬于激活狀態(tài)贞岭,激活狀態(tài)的實(shí)體有更新,刪除搓侄,刷新方法; active = true, // 給這個(gè)表指定一個(gè)名字瞄桨,默認(rèn)情況下是名字是類名 nameInDb = "AWESOME_USERS", // 可以給多個(gè)屬性定義索引和其他屬性.indexes = { @Index(value = "name DESC", unique = true) }, //是否使用GreenDao創(chuàng)建該表.createInDb = false, // 是否所有的屬性構(gòu)造器都應(yīng)該被生成,無參構(gòu)造器總是被要求generateConstructors = true, // 如果該類中沒有set get方法是否自動(dòng)生成 generateGettersSetters = true
基本注釋屬性
@ID 一般會(huì)選擇long/Long屬性作為Entity ID(即數(shù)據(jù)庫(kù)中的主鍵)autoincrement=true表示主鍵會(huì)自增如果false就會(huì)使用舊值
@Property 可以自定義一個(gè)該屬性在數(shù)據(jù)庫(kù)中的名稱讶踪,默認(rèn)情況下數(shù)據(jù)庫(kù)中該屬性名稱是Bean對(duì)象中的 屬性名但是不是以駝峰式而是以大寫與下劃線組合形式來命名的比如:customName將命名為 CUSTOM_NAME;注意:外鍵不能使用該屬性芯侥;
@NotNull 確保屬性值不會(huì)為null值;
**@Transient **使用該注釋的屬性不會(huì)被存入數(shù)據(jù)庫(kù)中;
@Unique
將屬性變成唯一約束屬性;也就是說在數(shù)據(jù)庫(kù)中該值必須唯一
@Generated
提示開發(fā)者該屬性不能被修改;并且實(shí)體類的方法乳讥,屬性柱查,構(gòu)造器一旦被@Generated注釋就不能被再次修改,否則或報(bào)錯(cuò)
Error:Execution failed for task ':app:greendao'.> Constructor (seeExampleEntity:21) has been changed after generation.Please either markit with @Keep annotation instead of @Generated to keep it untouched,oruse @Generated (without hash) to allow to replace it.
這是因?yàn)樵谕ㄟ^javabean對(duì)象自動(dòng)生成entities類時(shí)云石,greenDao會(huì)增加實(shí)體類代碼唉工,@Generated注釋部分與GreenDao增加的代碼相關(guān),胡亂修改@Generated代碼留晚,就會(huì)導(dǎo)致entities部分屬性與javabean不匹配導(dǎo)致報(bào)錯(cuò)酵紫;有倆種方法可以避免這種錯(cuò)誤
還原@Generated 改動(dòng)的部分告嘲,當(dāng)然你也可以完全刪除@Generated 注釋的部分下一次 app build時(shí)將會(huì)自動(dòng)生成错维;
使用@Keep 代替@Generated 這將告訴greenDao 不會(huì)使用該屬性注釋的代碼,但是這種改變可能會(huì)破壞entities類和greenDAO的其他部分的連接橄唬;注意:默認(rèn)情況下 greenDao會(huì)使用合理的默認(rèn)值去設(shè)置實(shí)體類赋焕,因此開發(fā)者不需要為每個(gè)屬性都添加注釋
@Entitypublic class User { @Id(autoincrement = true) private Long id; @Property(nameInDb = "USERNAME") private String name; @NotNull private int repos; @Transient private int tempUsageCount;...}
主鍵限制
每個(gè)實(shí)體類都應(yīng)該有一個(gè)long或者LONG型屬性作為主鍵;如果你不想用long或者LONG型作為主鍵仰楚,你可以使用一個(gè)唯一索引(使用@Index(unique = true)注釋使普通屬性改變成唯一索引屬性)屬性作為關(guān)鍵屬性隆判。
@Id
private Long id;
@Index(unique = true)
private String key;
索引屬性
使用@Index 可以將一個(gè)屬性變?yōu)閿?shù)據(jù)庫(kù)索引犬庇;其有倆個(gè)參數(shù)
name :不使用默認(rèn)名稱,自定義索引名稱
unique : 給索引增加一個(gè)唯一約束侨嘀,迫使該值唯一
@Entitypublic class User {@Id private Long id; @Index(unique = true) private String name;}
核心代碼初始化
// 下面代碼僅僅需要執(zhí)行一次臭挽,一般會(huì)放在application
helper = new DaoMaster.DevOpenHelper(this, "notes-db", null);
db = helper.getWritableDatabase();daoMaster = new DaoMaster(db);daoSession = daoMaster.newSession();
// 在activity或者fragment中獲取Dao對(duì)象
noteDao = daoSession.getNoteDao()
完成以上所有工作以后,我們的數(shù)據(jù)庫(kù)就已經(jīng)自動(dòng)生成了咬腕,接下來就可以對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作了欢峰;
增刪改查
greenDao的增,刪 涨共,改操作比較簡(jiǎn)單分別調(diào)用insert(),delete(),update()方法即可纽帖,save()方法比較特殊既能進(jìn)行插入操作也能執(zhí)行修改操作這個(gè)具體的可以查看greenDaoAPI
Query
與原生SQLitedatabases的查詢操作相比,greenDao Query簡(jiǎn)直不能再簡(jiǎn)單;greenDao 使用QueryBuilder構(gòu)建查詢語(yǔ)句也支持原生的SQL查詢語(yǔ)句
簡(jiǎn)單的查詢語(yǔ)句 在用戶表中查詢叫姓“Joe”的所有的用戶:
List joes = userDao.queryBuilder().where(Properties.FirstName.eq("Joe")).orderAsc(Properties.LastName) .list();
嵌套挑去查詢語(yǔ)句:查詢一個(gè)出生在1970年10月或者以后的"joe"用戶
QueryBuilder qb = userDao.queryBuilder();qb.where(Properties.FirstName.eq("Joe"),//第一個(gè)約束條件姓喬qb.or(Properties.YearOfBirth.gt(1970),//或者出生日期大于1970年qb.and(Properties.YearOfBirth.eq(1970),Properties.MonthOfBirth.ge(10))//并且在1970年出生 但是月份大于10月的));List youngJoes = qb.list();
greenDao除了eq()操作之外還有很多其他方法大大方便了我們?nèi)粘2樵儾僮鞅热纾?/p>
eq():==
noteq():!=
gt(): >
lt():<
ge:>=
le:<=
like():包含
between:倆者之間
in:在某個(gè)值內(nèi)
notIn:不在某個(gè)值內(nèi)
**分頁(yè)查詢 **
limit(int): 限制查詢的數(shù)量;
offset(int): 每次返回的數(shù)量; offset不能單獨(dú)使用举反;
**查詢與LazyList類 **
Query : Query類表示一個(gè)查詢能夠執(zhí)行很多次;而當(dāng)通過QueryBuilder的任何查詢方法(eg:list())來獲取查詢結(jié)果時(shí)懊直,querybuilder都會(huì) 在其內(nèi)部創(chuàng)建Query來執(zhí)行查詢語(yǔ)句的;如果執(zhí)行多次查詢應(yīng)該使用Query對(duì)象; 如果只想獲取一個(gè)結(jié)果時(shí)可以使用Query(or QueryBuilder)中的unique()方法;
LazyList : 可以通過以下方法獲取查詢結(jié)果集合;
list() 緩存查詢結(jié)果;list()類型一般為ArrayList
listLazy() 懶查詢,只有當(dāng)調(diào)用list()中的實(shí)體對(duì)象時(shí)才會(huì)執(zhí)行查詢操作并且只緩存第一次被查詢的結(jié)果火鼻,需要關(guān)閉
listlazyUncached() 懶查詢,只有當(dāng)調(diào)用list()中的實(shí)體對(duì)象時(shí)才會(huì)執(zhí)行查詢操作并且不緩存;
listIterator() 對(duì)查詢結(jié)果進(jìn)行遍歷室囊,不緩存,需要關(guān)閉;后面三個(gè)類是LazyList中的方法魁索,LazyList為了執(zhí)行不同的緩存策略其內(nèi)部持有數(shù)據(jù)庫(kù)的cursor對(duì)象波俄;
一般情況下這三個(gè)方法執(zhí)行完畢后會(huì)自動(dòng)關(guān)閉cursor;但是防止在還沒有執(zhí)行完查詢結(jié)果時(shí)蛾默,對(duì)象被終結(jié)cursor還是無法被關(guān)閉的情況發(fā)生懦铺,需要手動(dòng)關(guān)閉close();
多次執(zhí)行查詢語(yǔ)句
Query對(duì)象一旦生成就能多次被使用,你也可以為下一次查詢?cè)黾硬樵儣l件
// fetch users with Joe as a first name born in 1970Query
query = userDao.queryBuilder().where(
Properties.FirstName.eq("Joe"),
Properties.YearOfBirth.eq(1970)).build();List joesOf1970 =
query.list(); // using the same Query object, we can change the
parameters// to search for Marias born in 1977
later:query.setParameter(0, "Maria");query.setParameter(1,
1977);List mariasOf1977 = query.list();
在多線程執(zhí)行查詢
如果有多條線程執(zhí)行查詢語(yǔ)句時(shí)需要調(diào)用forCurrentThread()方法將query對(duì)象與當(dāng)前線程進(jìn)行綁定支鸡,如果其他線程修改該Query對(duì)象冬念,greenDao將會(huì)拋出一個(gè)異常;forCurrentThread()方法通過將Query創(chuàng)建時(shí)的時(shí)間作為 query標(biāo)識(shí);
使用SQL查詢
如果QueryBuilder不能滿足需求可以使用以下倆種方法來實(shí)現(xiàn)你的需求;
首選方法用SQL語(yǔ)句:
Query query = userDao.queryBuilder().where( new
StringCondition("_ID IN " + "(SELECT USER_ID FROM
USER_MESSAGE WHERE READ_FLAG = 0)")).build();
備選方法 :
使用queryRaw 或者queryRawCreate:
Query query = userDao.queryRawCreate( ", GROUP G WHEREG.NAME=? AND T.GROUP_ID=G._ID", "admin");
好了牧挣,GreenDao的介紹到這里就結(jié)束了急前,本期主要講解了greenDao的基本概念與基本操作。