史上最高效的ORM方案—GreenDao3.0詳解

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的基本概念與基本操作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瀑构,一起剝皮案震驚了整個(gè)濱河市裆针,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌寺晌,老刑警劉巖世吨,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異呻征,居然都是意外死亡耘婚,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門陆赋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沐祷,“玉大人嚷闭,你說我怎么就攤上這事±盗伲” “怎么了胞锰?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)兢榨。 經(jīng)常有香客問我胜蛉,道長(zhǎng),這世上最難降的妖魔是什么色乾? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任誊册,我火速辦了婚禮,結(jié)果婚禮上暖璧,老公的妹妹穿的比我還像新娘案怯。我一直安慰自己,他們只是感情好澎办,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布嘲碱。 她就那樣靜靜地躺著,像睡著了一般局蚀。 火紅的嫁衣襯著肌膚如雪麦锯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天琅绅,我揣著相機(jī)與錄音扶欣,去河邊找鬼。 笑死千扶,一個(gè)胖子當(dāng)著我的面吹牛料祠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播澎羞,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼髓绽,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了妆绞?” 一聲冷哼從身側(cè)響起顺呕,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎括饶,沒想到半個(gè)月后株茶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡巷帝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年忌卤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了扫夜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片楞泼。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡驰徊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出堕阔,到底是詐尸還是另有隱情棍厂,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布超陆,位于F島的核電站牺弹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏时呀。R本人自食惡果不足惜张漂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谨娜。 院中可真熱鬧航攒,春花似錦、人聲如沸趴梢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)坞靶。三九已至憔狞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間彰阴,已是汗流浹背瘾敢。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留尿这,地道東北人廉丽。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像妻味,于是被迫代替她去往敵國(guó)和親正压。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • GreenDao 介紹:greenDAO是一個(gè)對(duì)象關(guān)系映射(ORM)的框架责球,能夠提供一個(gè)接口通過操作對(duì)象的方式去操...
    小董666閱讀 733評(píng)論 0 1
  • 目錄 session 緩存 多表關(guān)聯(lián) 多表查詢 自定義參數(shù)類型 與數(shù)據(jù)庫(kù)操作相關(guān)的AS插件 session 緩存 ...
    看一季殘花落幕閱讀 1,245評(píng)論 1 1
  • greenDAO greenDAO 是一個(gè)將對(duì)象映射到 SQLite 數(shù)據(jù)庫(kù)中的輕量且快速的 ORM 解決方案焦履。它...
    蕉下孤客閱讀 16,097評(píng)論 18 104
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)雏逾,斷路器嘉裤,智...
    卡卡羅2017閱讀 134,659評(píng)論 18 139
  • 效果圖 實(shí)現(xiàn)思路 自定義Dialog,為Dialog添加自定義布局栖博,自定義PagerAdapter以及PageTr...
    轉(zhuǎn)音視頻的老王閱讀 2,672評(píng)論 0 17