GreenDao3.0入門
1. 什麼是greenDao
弄明白greenDao之前我們應該先了解什麼是ORM(Object Relation Mapping 即 物件關係對映),說白了就是將面向物件程式語言裡的物件與資料庫關聯起來的一種技術,而greenDao就是實現這種技術之一,所以說greenDao其實就是一種將java object 與SQLite Database關聯起來的橋樑,它們之間的關係 如下圖所示;
greenDao ,SQLite Database與Java Object物件之間的關係
2. 為什麼要使用greenDao
greenDao可以說是當今最流行,最高效而且還在迭代的關係型資料庫。而且greenDao3.0還支援RxJava操作,greenDao如此受歡迎離不開以下幾點:
- 存取速度快
每秒中可以操作數千個實體 下圖是幾種常見關係型資料庫效能比較;
幾種常用資料庫比較 - 支援資料庫加密
支援android原生的資料庫SQLite,也支援SQLCipher(在SQLite基礎上加密型資料庫)。 - 輕量級
greenDao的程式碼庫僅僅100k大小 - 啟用實體
處於啟用狀態下的實體可以有更多操作方法 - 支援快取
能夠將使用的過的實體存在快取中,下次使用時可以直接從快取中取,這樣可以使效能提高N個數量級 - 程式碼自動生成
greenDao 會根據modle類自動生成實體類(entities)和Dao物件,並且Dao物件是根據entities類量身定做的並且一 一對應。
3. 怎樣使用greenDao
3.1 入門
3.1.1 配置GreenDao
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.0'//greenDao生產程式碼外掛
}
apply plugin: 'org.greenrobot.greendao'//greendao外掛
dependencies {
compile 'org.greenrobot:greendao:3.2.0'
配置資料庫資訊
greendao {
//資料庫schema版本,也可以理解為資料庫版本號
schemaVersion 2
//設定DaoMaster 、DaoSession、Dao包名
daoPackage 'com.qhn.bhne.footprinting.db'
//設定DaoMaster 、DaoSession、Dao目錄
targetGenDir 'src/main/java'
//設定生成單元測試目錄
// targetGenDirTest
//設定自動生成單元測試用例
// generateTests
}
到這裡資料庫基本配置已經完成,接下來讓我們一起來了解下greenDao的核心類該怎樣使用吧。
3.1.2 核心類介紹
greenDao核心類構成
-
DaoMaster:
- 是GreenDao的入口也是greenDao頂級物件,對於一個指定的表單持有資料庫物件(SQLite資料庫)並且能夠管理DAO類
- 能夠建立表和刪除表
- 其內部類OpenHelper 與DevOpenHelper是建立SQlite資料庫的SQLiteOpenHelper的具體實現
-
DaoSession:
- 對於一個指定的表單可以管理所有的Dao 物件。
- 也能夠對實體類執行 insert ,load,update,refresh.delete操作。
- DaoSession也能跟蹤 identity scope:即session查詢後的實體會存在快取中,並給該實體生成一個flag來追蹤該實體,下次再次查詢時會直接從快取中取出來而不是從資料庫中取出來
- DAOS
- 能夠持久訪問和查詢實體類
- 比起DaoSession有更多的持久化方法 count, loadAll,insertInt等等;
- Entities - 自動生成的程式碼,一般情況下與javaBean物件的屬性一一對應。
3.1.3 構建Model類
Molde類需要用java類來定義並且可以通過GreenDao中的註釋來表明Model中的每個屬性在資料庫的中該如何定義;定義model類後點擊Make project選項GreenDao就會自動生成DaoMaster,DaoSession,和DAOS類,生成的程式碼將會儲存在預先在budle gradle中設定的位置
- 實體和註釋
GreenDao 通過註釋來定義表單與實體
@Entity
public class User {
@Id
private Long id; private String name;
@Transient
private int tempUsageCount; // 沒有存入資料庫中
}
@Entity
- 告訴GreenDao 該Bean類需要持久化。只有使用@Entity註釋的Bean類才能被dao類操作;
- @Entity可以在不使用引數下使用,但是也可以給Entity配置引數,其引數如下
//如果該實體屬於多個表單,可以使用該引數;
schema = "myschema",
// 該實體屬於啟用狀態,啟用狀態的實體有更新,刪除,重新整理方法;
active = true,
// 給這個表指定一個名字,預設情況下是名字是類名
nameInDb = "AWESOME_USERS",
// 可以給多個屬性定義索引和其他屬性.
indexes = { @Index(value = "name DESC", unique = true) },
//是否使用GreenDao建立該表.
createInDb = false,
// 是否所有的屬性構造器都應該被生成,無參構造器總是被要求
generateConstructors = true,
// 如果該類中沒有set get方法是否自動生成
generateGettersSetters = true
-
基本註釋屬性
-
@ID 一般會選擇long/Long屬性作為Entity ID(即資料庫中的主鍵)autoincrement=true表示主鍵會自增如果false就會使用舊值
-
@Property 可以自定義一個該屬性在資料庫中的名稱,預設情況下資料庫中該屬性名稱是Bean物件中的 屬性名但是不是以駝峰式而是以大寫與下劃線組合形式來命名的比如:customName將命名為 CUSTOM_NAME;注意:外來鍵不能使用該屬性;
-
@NotNull 確保屬性值不會為null值;
-
@Transient 使用該註釋的屬性不會被存入資料庫中;
-
@Unique 將屬性變成唯一約束屬性;也就是說在資料庫中該值必須唯一
-
@Generated 提示開發者該屬性不能被修改;並且實體類的方法,屬性,構造器一旦被@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.
這是因為在通過javabean物件自動生成entities類時,greenDao會增加實體類程式碼,@Generated註釋部分與GreenDao增加的程式碼相關,胡亂修改@Generated程式碼,就會導致entities部分屬性與javabean不匹配導致報錯;有倆種方法可以避免這種錯誤
-
還原@Generated 改動的部分,當然你也可以完全刪除@Generated 註釋的部分下一次 app build時將會自動生成;
-
使用@Keep 代替@Generated 這將告訴greenDao 不會使用該屬性註釋的程式碼,但是這種改變可能會破壞entities類和greenDAO的其他部分的連線;注意:預設情況下 greenDao會使用合理的預設值去設定實體類,因此開發者不需要為每個屬性都添加註釋
-
-
@Entity
public class User {
@Id(autoincrement = true)
private Long id;
@Property(nameInDb = "USERNAME")
private String name;
@NotNull
private int repos;
@Transient
private int tempUsageCount;
...}
- 主鍵限制
每個實體類都應該有一個long或者LONG型屬性作為主鍵;如果你不想用long或者LONG型作為主鍵,你可以使用一個唯一索引(使用@Index(unique = true)註釋使普通屬性改變成唯一索引屬性)屬性作為關鍵屬性。
@Id
private Long id;
@Index(unique = true)
private String key;
- 索引屬性
使用@Index 可以將一個屬性變為資料庫索引;其有倆個引數- name :不使用預設名稱,自定義索引名稱
- unique : 給索引增加一個唯一約束,迫使該值唯一
@Entity
public class User {
@Id
private Long id;
@Index(unique = true)
private String name;
}
-
核心程式碼初始化
建立資料庫過程// 下面程式碼僅僅需要執行一次,一般會放在application helper = new DaoMaster.DevOpenHelper(this, "notes-db", null); db = helper.getWritableDatabase(); daoMaster = new DaoMaster(db); daoSession = daoMaster.newSession(); // 在activity或者fragment中獲取Dao物件 noteDao = daoSession.getNoteDao()
完成以上所有工作以後,我們的資料庫就已經自動生成了,接下來就可以對資料庫進行操作了;
-
增刪改查
greenDao的增,刪 ,改操作比較簡單分別呼叫insert(),delete(),update()方法即可,save()方法比較特殊既能執行插入操作也能執行修改操作這個具體的可以檢視greenDaoAPI-
Query
與原生SQLitedatabases的查詢操作相比,greenDao Query簡直不能再簡單;greenDao 使用QueryBuilder構建查詢語句也支援原生的SQL查詢語句- 簡單的查詢語句 在使用者表中查詢叫姓“Joe”的所有的使用者:
List joes = userDao.queryBuilder() .where(Properties.FirstName.eq("Joe")) .orderAsc(Properties.LastName) .list();
- 巢狀挑去查詢語句:查詢一個出生在1970年10月或者以後的"joe"使用者
greenDao除了eq()操作之外還有很多其他方法大大方便了我們日常查詢操作比如:QueryBuilder qb = userDao.queryBuilder(); qb.where(Properties.FirstName.eq("Joe"),//第一個約束條件姓喬 qb.or(Properties.YearOfBirth.gt(1970),//或者出生日期大於1970年 qb.and(Properties.YearOfBirth.eq(1970), Properties.MonthOfBirth.ge(10))//並且在1970年出生 但是月份大於 10月的)); List youngJoes = qb.list();
- eq():==
- noteq():!=
- gt(): >
- lt():<
- ge:>=
- le:<=
- like():包含
- between:倆者之間
- in:在某個值內
- notIn:不在某個值內
- 簡單的查詢語句 在使用者表中查詢叫姓“Joe”的所有的使用者:
-
-
分頁查詢
- limit(int): 限制查詢的數量;
- offset(int): 每次返回的數量; offset不能單獨使用;
-
查詢與LazyList類
-
Query : Query類表示一個查詢能夠執行很多次;而當通過QueryBuilder的任何查詢方法(eg:list())來獲取查詢結果時,querybuilder都會 在其內部建立Query來執行查詢語句的;如果執行多次查詢應該使用Query物件; 如果只想獲取一個結果時可以使用Query(or QueryBuilder)中的unique()方法;
-
LazyList : 可以通過以下方法獲取查詢結果集合;
-
list() 快取查詢結果;list()型別一般為ArrayList
-
listLazy() 懶查詢,只有當呼叫list()中的實體物件時才會執行查詢操作並且只快取第一次被查詢的結果,需要關閉
-
listlazyUncached() 懶查詢,只有當呼叫list()中的實體物件時才會執行查詢操作並且不快取;
-
listIterator() 對查詢結果進行遍歷,不快取,需要關閉;
-
-
後面三個方法是LazyList類中的方法,LazyList為了執行不同的快取策略其內部持有資料庫的cursor物件;一般情況下這三個方法執行完畢後會自動關閉cursor;但是防止在還沒有執行完查詢結果時,物件被終結cursor還是無法被關閉的情況發生,需要手動關閉close();
- 多次執行查詢語句
Query物件一旦生成就能多次被使用,你也可以為下一次查詢增加查詢條件
// 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();
-
在多執行緒執行查詢
如果有多條執行緒執行查詢語句時需要呼叫forCurrentThread()方法將query物件與當前執行緒進行繫結,如果其他執行緒修改該Query物件,greenDao將會丟擲一個異常;forCurrentThread()方法通過將Query建立時的時間作為 query標識; -
使用SQL查詢
如果QueryBuilder不能滿足需求可以使用以下倆種方法來實現你的需求;- 首選方法用SQL語句:
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 WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin");
- 首選方法用SQL語句:
好了這一期的GreenDao的介紹到這裡就結束了,本期主要講解了greenDao的基本概念與基本操作,下一期(史上最高效的ORM方案——GreenDao3.0高階用法)我會介紹GreenDao的高階操作:session快取,多表查詢,多表關聯,自定義引數型別。如果你覺得本篇本章有什麼不足的地方歡迎在評論區留言;